Cách hợp nhất hai mảng trong JavaScript và các mục không trùng lặp


1367

Tôi có hai mảng JavaScript:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

Tôi muốn đầu ra là:

var array3 = ["Vijendra","Singh","Shakya"];

Các mảng đầu ra nên có từ lặp đi lặp lại loại bỏ.

Làm cách nào để hợp nhất hai mảng trong JavaScript để tôi chỉ nhận được các mục duy nhất từ ​​mỗi mảng theo cùng thứ tự chúng được chèn vào mảng ban đầu?


1
Trước khi bạn đăng câu trả lời mới, hãy xem xét đã có hơn 75 câu trả lời cho câu hỏi này. Xin vui lòng, đảm bảo rằng câu trả lời của bạn đóng góp thông tin không nằm trong số các câu trả lời hiện có.
janniks

[... Bộ mới ([... [1, 2, 3], ... [2, 3, 4]])] kết quả [1, 2, 3, 4]
Denis Giffeler

Thay vào đó, nếu bạn muốn một giải pháp chung chung hơn bao gồm sự hợp nhất sâu sắc, hãy xem câu hỏi này . Một số câu trả lời bao gồm các mảng là tốt.
Martin Braun

Câu trả lời:


1665

Để chỉ hợp nhất các mảng (mà không loại bỏ trùng lặp)

Sử dụng phiên bản ES5 Array.concat:

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];

console.log(array1.concat(array2));

Phiên bản ES6 sử dụng phá hủy

const array1 = ["Vijendra","Singh"];
const array2 = ["Singh", "Shakya"];
const array3 = [...array1, ...array2];

Vì không có cách nào được xây dựng để loại bỏ các bản sao ( ECMA-262 thực sự có Array.forEachích cho việc này), chúng tôi phải thực hiện thủ công:

Array.prototype.unique = function() {
    var a = this.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
};

Sau đó, để sử dụng nó:

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
// Merges both arrays and gets unique items
var array3 = array1.concat(array2).unique(); 

Điều này cũng sẽ duy trì thứ tự của các mảng (nghĩa là không cần sắp xếp).

Vì nhiều người cảm thấy khó chịu về việc tăng nguyên mẫu Array.prototypefor incác vòng lặp, nên đây là một cách ít xâm lấn hơn để sử dụng nó:

function arrayUnique(array) {
    var a = array.concat();
    for(var i=0; i<a.length; ++i) {
        for(var j=i+1; j<a.length; ++j) {
            if(a[i] === a[j])
                a.splice(j--, 1);
        }
    }

    return a;
}

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];
    // Merges both arrays and gets unique items
var array3 = arrayUnique(array1.concat(array2));

Đối với những người may mắn làm việc với các trình duyệt có sẵn ES5, bạn có thể sử dụng Object.definePropertynhư thế này:

Object.defineProperty(Array.prototype, 'unique', {
    enumerable: false,
    configurable: false,
    writable: false,
    value: function() {
        var a = this.concat();
        for(var i=0; i<a.length; ++i) {
            for(var j=i+1; j<a.length; ++j) {
                if(a[i] === a[j])
                    a.splice(j--, 1);
            }
        }

        return a;
    }
});

281
Lưu ý rằng thuật toán này là O (n ^ 2).
Gumbo

7
Hãy để [a, b, c][x, b, d]là các mảng (giả sử trích dẫn). concat cho [a, b, c, x, b, d]. Sẽ không phải là đầu ra duy nhất () [a, c, x, b, d]. Điều đó không bảo toàn thứ tự tôi nghĩ - tôi tin OP muốn[a, b, c, x, d]
Amarghosh

89
OP đã chấp nhận câu trả lời đầu tiên khiến anh ấy làm việc và ký tắt. Chúng tôi vẫn đang so sánh các giải pháp của nhau, tìm lỗi sửa lỗi, cải thiện hiệu suất, đảm bảo tính tương thích của nó ở mọi nơi và v.v ... Vẻ đẹp của stackoverflow :-)
Amarghosh

6
Ban đầu tôi đã bỏ phiếu này nhưng đã thay đổi suy nghĩ của tôi. Việc gán các nguyên mẫu cho Array.prototype có hậu quả của việc phá vỡ các câu lệnh "for ... in". Vì vậy, giải pháp tốt nhất có lẽ là sử dụng một chức năng như thế này nhưng không chỉ định nó làm nguyên mẫu. Một số người có thể lập luận rằng không nên sử dụng các câu lệnh "for ... in" để lặp lại các phần tử mảng, nhưng mọi người thường sử dụng chúng theo cách đó để ít nhất giải pháp này được sử dụng một cách thận trọng.
Chỉ huy mã

16
bạn nên luôn luôn sử dụng for ... invới hasOwnPropertytrong trường hợp này phương pháp nguyên mẫu là tốt
mulllhausen

600

Với Underscore.js hoặc Lo-Dash, bạn có thể làm:

console.log(_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

http://underscorejs.org/#union

http://lodash.com/docs#union


70
Hoặc, có lẽ thậm chí còn tốt hơn so với gạch dưới, lodash tương thích API .
Brian M. Hunt

3
@Ygg Từ các tài liệu lodash. "Trả về một mảng mới của các giá trị duy nhất, theo thứ tự , hiện diện trong một hoặc nhiều mảng."
Richard Ayotte

4
Tôi thích underscore.js. Những gì tôi đã kết thúc bằng cách sử dụng là underscore.flatten(), tốt hơn so với liên minh ở chỗ nó cần một mảng các mảng.
thợ dệt

8
@weaver _.flatten hợp nhất, nhưng không 'không trùng lặp'.
GijsjanB

9
Hiệu suất nhanh chóng thực hiện lodash so với câu trả lời hàng đầu: jsperf.com/merge-two-arrays-keep-only-unique-values
slickplaid

288

Đầu tiên nối hai mảng, tiếp theo chỉ lọc các mục duy nhất:

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b)
var d = c.filter((item, pos) => c.indexOf(item) === pos)

console.log(d) // d is [1, 2, 3, 101, 10]

Biên tập

Theo đề xuất, một giải pháp khôn ngoan hơn về hiệu suất sẽ là lọc ra các mục duy nhất btrước khi nối với a:

var a = [1, 2, 3], b = [101, 2, 1, 10]
var c = a.concat(b.filter((item) => a.indexOf(item) < 0))

console.log(c) // c is [1, 2, 3, 101, 10]


5
Giải pháp ban đầu ở đây có lợi ích là loại bỏ các bản sao trong mỗi mảng nguồn. Tôi đoán nó phụ thuộc vào bối cảnh của bạn mà bạn sẽ sử dụng.
theGecko

Bạn có thể hợp nhất khác nhau cho hỗ trợ IE6: c = Array.from (Bộ mới (c));
Tobi G.

Nếu tôi thực sự muốn thay đổi ađể thêm b, thì tốt hơn là nên lặp lại và sử dụng đẩy? a.forEach(function(item){ if(a.indexOf(item)<0) a.push(item); });
kinh ngạc

1
Chỉ cần một lời nhắc nhở về việc sử dụng trình duyệt hiện tại caniuse.com/usage-table cho những người lo lắng về IE6.
pmrotule

10
@ Andrew: Thậm chí tốt hơn: 1. var c = [...a, ...b.filter(o => !~a.indexOf(o))]; 2. var c = [...new Set([...a, ...b])];
7vujy0f0hy

203

Đây là giải pháp ECMAScript 6 sử dụng toán tử trải và tổng quát mảng.

Hiện tại nó chỉ hoạt động với Firefox và có thể là Internet Explorer Technical Preview.

Nhưng nếu bạn sử dụng Babel , bạn có thể có nó ngay bây giờ.

const input = [
  [1, 2, 3],
  [101, 2, 1, 10],
  [2, 1]
];
const mergeDedupe = (arr) => {
  return [...new Set([].concat(...arr))];
}

console.log('output', mergeDedupe(input));


14
Điều này nên được thêm vào câu trả lời được chấp nhận. Giải pháp này hiệu quả và thanh lịch hơn nhiều so với những gì hiện có thể có nhưng đó là điều chắc chắn chúng tôi sẽ có thể làm được (và nên làm để theo kịp lĩnh vực này).
EmmaGamma

Đây không phải là câu hỏi tương tự như câu hỏi của OP (điều này dường như là một bản đồ phẳng hơn bất cứ điều gì) nhưng upvote bởi vì nó tuyệt vời.
jedd.ahyoung

4
Khó có thể nói rằng đây phải là câu trả lời được chấp nhận vì câu hỏi là từ năm 2009. Nhưng vâng, đây không chỉ là "biểu diễn" mà còn "thanh lịch"
Cezar Augusto

11
Array.fromcó thể được sử dụng thay cho toán tử lây lan: Array.from(new Set([].concat(...arr)))
Henry Blyth

1
Điều này rất thanh lịch. Thật không may, Typecript không hỗ trợ này. stackoverflow.com/questions/33464504/ từ
Cá chép Ben

190

ES6

array1.push(...array2) // => don't remove duplication 

HOẶC LÀ

[...array1,...array2] //   =>  don't remove duplication 

HOẶC LÀ

[...new Set([...array1 ,...array2])]; //   => remove duplication

1
Ví dụ thứ 1/2 hoàn toàn không có union+ Ví dụ thứ 1 làm nổ tung ngăn xếp cho Arrays lớn + ví dụ thứ 3 cực kỳ chậm và tiêu tốn rất nhiều bộ nhớ, vì hai Arrays trung gian phải được xây dựng + ví dụ thứ 3 chỉ có thể được sử dụng cho unionmột cái đã biết số Arrays tại thời gian biên dịch.

vậy làm thế nào bạn sẽ làm điều đó?
David Noreña

14
Setlà cách để đi đến đây
philk

3
Lưu ý rằng đối với tập hợp không thể lặp lại hai đối tượng có cùng cặp giá trị khóa trừ khi chúng là cùng một tham chiếu đối tượng.
Jun711

2
Không hoạt động với một mảng các đối tượng, vì nó sẽ chỉ hợp nhất các tham chiếu đối tượng và không quan tâm nếu các đối tượng đó bằng nhau.
Wilson Biggie

87

Sử dụng một bộ (ECMAScript 2015), nó sẽ đơn giản như sau:

const array1 = ["Vijendra", "Singh"];
const array2 = ["Singh", "Shakya"];
console.log(Array.from(new Set(array1.concat(array2))));


7
Tôi coi đây là "Câu trả lời được chấp nhận" khi sử dụng ES6.
mwieczorek

9
@mwieczorek Làm thế nào về:const array3 = [...new Set(array1.concat(array2))]
Robby Cornelissen

5
Nó không hoạt động nếu bạn đang sử dụng Mảng các đối tượng
carkod

1
để hợp nhất các đối tượng khác nhau mà không trùng lặp: stackoverflow.com/a/54134237/3131433
Rakibul Haq

38

Đây là một chút khác nhau về vòng lặp. Với một số tối ưu hóa trong phiên bản Chrome mới nhất, đây là phương pháp nhanh nhất để giải quyết sự kết hợp của hai mảng (Chrome 38.0.2111).

http://jsperf.com/merge-two-arrays-keep-only-unique-values

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [];

var arr = array1.concat(array2),
  len = arr.length;

while (len--) {
  var itm = arr[len];
  if (array3.indexOf(itm) === -1) {
    array3.unshift(itm);
  }
}

vòng lặp while: ~ 589k ops / s
bộ lọc: ~ 445k ops / s
lodash: 308k ops / s
cho các vòng lặp: 225k ops / s

Một bình luận chỉ ra rằng một trong các biến thiết lập của tôi đã khiến vòng lặp của tôi vượt lên trên phần còn lại, bởi vì nó không phải khởi tạo một mảng trống để ghi vào. Tôi đồng ý với điều đó, vì vậy tôi đã viết lại bài kiểm tra cho cả sân chơi và bao gồm một tùy chọn thậm chí còn nhanh hơn.

http://jsperf.com/merge-two-arrays-keep-only-unique-values/52

let whileLoopAlt = function (array1, array2) {
    const array3 = array1.slice(0);
    let len1 = array1.length;
    let len2 = array2.length;
    const assoc = {};

    while (len1--) {
        assoc[array1[len1]] = null;
    }

    while (len2--) {
        let itm = array2[len2];

        if (assoc[itm] === undefined) { // Eliminate the indexOf call
            array3.push(itm);
            assoc[itm] = null;
        }
    }

    return array3;
};

Trong giải pháp thay thế này, tôi đã kết hợp một giải pháp mảng kết hợp để loại bỏ .indexOf() cuộc gọi trong vòng lặp làm chậm mọi thứ với vòng lặp thứ hai và bao gồm một số tối ưu hóa khác mà người dùng khác đã đề xuất trong câu trả lời của họ. .

Câu trả lời hàng đầu ở đây với vòng lặp kép trên mỗi giá trị (i-1) vẫn chậm hơn đáng kể. lodash vẫn đang hoạt động mạnh mẽ và tôi vẫn muốn giới thiệu nó cho bất cứ ai không ngại thêm thư viện vào dự án của họ. Đối với những người không muốn, vòng lặp while của tôi vẫn là một câu trả lời hay và câu trả lời của bộ lọc đã thể hiện rất mạnh ở đây, đánh bại tất cả các bài kiểm tra của tôi với Canary Chrome mới nhất (44.0.2360) khi viết bài này.

Kiểm tra câu trả lời của Mikecâu trả lời của Dan Stocker nếu bạn muốn tăng tốc độ lên. Đó là những kết quả nhanh nhất trong tất cả các kết quả sau khi trải qua gần như tất cả các câu trả lời khả thi.


Có một lỗ hổng trong phương pháp luận của bạn: bạn đặt việc tạo mảng 3 vào giai đoạn thiết lập, trong khi chi phí đó chỉ là một phần trong điểm số của giải pháp dựa trên cơ sở của bạn. Với 1 dòng này được di chuyển , giải pháp của bạn rơi vào tốc độ của vòng lặp for. Tôi hiểu rằng mảng đó có thể được sử dụng lại, nhưng có lẽ các thuật toán khác cũng có thể có lợi từ việc không phải khai báo và khởi tạo mọi khối xây dựng cần thiết.
doldt

Tôi đồng ý với tiền đề của bạn @doldt, nhưng không đồng ý với kết quả của bạn. Có một lỗ hổng thiết kế cơ bản với việc loại bỏ các mục dựa trên vòng lặp, trong đó bạn phải kiểm tra lại độ dài của mảng sau khi bạn đã xóa các mục, dẫn đến thời gian thực hiện chậm hơn. Một vòng lặp while hoạt động ngược không có các hiệu ứng này. Dưới đây là một ví dụ với việc loại bỏ càng nhiều biến thiết lập càng tốt mà tôi không thể thay đổi câu trả lời ban đầu của họ quá nhiều: jsperf.com/merge-two-arrays-keep-only-unique-values/19
slickplaid

@slickplaid các bài kiểm tra được liên kết là trống và phiên bản tiếp theo tại jsperf bị treo trong vòng lặp while.
doldt

@doldt Tôi đã giải quyết mối quan tâm của bạn trong câu trả lời của tôi và cũng đã thêm một bài kiểm tra cập nhật thích hợp cho nó. Hãy cho tôi biết nếu bạn đồng ý với những kết quả đó hay không. Ngoài ra, tôi đã thêm một kết quả tốt hơn bằng cách sử dụng một mảng kết hợp.
slickplaid

1
@slickplaid Cảm ơn bạn đã thiết lập trang perf mở rộng. Trừ khi tôi thiếu một cái gì đó, chức năng "whileLoopAlt2" không hoạt động? Nó tạo ra một mảng mới chứa mảng đầu tiên và mảng thứ hai (theo thứ tự ngược lại). Để tránh nhầm lẫn, tôi đã thực hiện một sửa đổi khác loại bỏ chức năng bị hỏng. Tôi cũng đã thêm một ví dụ bổ sung: jsperf.com/merge-two-arrays-keep-only-unique-values/22
Stephen S

37

Bạn có thể làm điều đó một cách đơn giản với ECMAScript 6,

var array1 = ["Vijendra", "Singh"];
var array2 = ["Singh", "Shakya"];
var array3 = [...new Set([...array1 ,...array2])];
console.log(array3); // ["Vijendra", "Singh", "Shakya"];
  • Sử dụng toán tử trải để ghép mảng.
  • Sử dụng Set để tạo một bộ phần tử riêng biệt.
  • Một lần nữa sử dụng toán tử trải rộng để chuyển đổi Set thành một mảng.

2
Tôi gặp lỗi: Loại 'Đặt <chuỗi>' không phải là kiểu mảng.
gattsbr

3
Và nếu bạn vì lý do nào đó không muốn sử dụng toán tử lây lan, thì cũng có : Array.from(new Set(array1.concat(array2))).
kba

@gattsbr, với TypeScript tsconfig.json, bạn có thể thêm "downlevelIteration": truevào compilerOptions.
VincentPerrin.com

19
Array.prototype.merge = function(/* variable number of arrays */){
    for(var i = 0; i < arguments.length; i++){
        var array = arguments[i];
        for(var j = 0; j < array.length; j++){
            if(this.indexOf(array[j]) === -1) {
                this.push(array[j]);
            }
        }
    }
    return this;
};

Một chức năng hợp nhất mảng tốt hơn nhiều.


4
var test = ['a', 'b', 'c']; console.log(test); sẽ in ["a", "b", "c", merge: function]
Mistidou

Giải pháp tuyệt vời. Tôi đã cập nhật bài kiểm tra jsperf được đăng ở trên bởi @slickplaid ( jsperf.com/merge-two-arrays-keep-only-unique-values/3 ) và có vẻ như đây là bài kiểm tra nhanh nhất.
Rắn hổ mang

@Cobra Có nguy cơ âm thanh nhỏ, chạy trên Chrome 40.0.2214 (Mới nhất kể từ ngày 18/2/15), câu trả lời này chậm hơn 53% so với của tôi. OTOH IE11 dường như không được tối ưu hóa cho câu trả lời của tôi. Mặc dù vậy, Chrome mobile vẫn làm rung chuyển nó. Thành thật mà nói, nếu bạn đang sử dụng lodash / _ mà hầu hết chúng ta nên, câu trả lời thực sự đã khá cao trong danh sách này. :)
slickplaid 18/2/2015

@slickplaid Đúng, và nó nhanh hơn một chút, thậm chí so với lodash / _ one. Có lẽ tôi sẽ kết thúc việc chuyển đổi triển khai của mình ở điểm này hay điểm khác sang thứ tương tự như của bạn. : D
Cobra

1
Không chắc chắn chi phí của phương thức indexOf () là gì nhưng đây có lẽ là phương thức tương thích ES5 nhanh nhất. Cũng không có giá trị gì mà độ dài thay đổi của các đối số là không cần thiết. Phương pháp này là chuỗi. @slickplaid Tải thư viện không bao giờ là câu trả lời cho câu hỏi "làm thế nào để làm điều đó trong javascript". chắc chắn nhiều thư viện có chức năng hoàn thành công việc 7 dòng này.
khởi động

19

Chỉ cần ném vào hai xu của tôi.

function mergeStringArrays(a, b){
    var hash = {};
    var ret = [];

    for(var i=0; i < a.length; i++){
        var e = a[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    for(var i=0; i < b.length; i++){
        var e = b[i];
        if (!hash[e]){
            hash[e] = true;
            ret.push(e);
        }
    }

    return ret;
}

Đây là một phương pháp tôi sử dụng rất nhiều, nó sử dụng một đối tượng làm bảng hashlookup để thực hiện kiểm tra trùng lặp. Giả sử rằng hàm băm là O (1), thì hàm này chạy trong O (n) trong đó n là a.length + b.length. Tôi thực sự không biết làm thế nào trình duyệt thực hiện băm, nhưng nó hoạt động tốt trên nhiều ngàn điểm dữ liệu.


Hoàn thành rất tốt. Đánh bại khá nhiều (nếu không phải tất cả) các kết quả khác trên trang này bằng cách tận dụng mảng kết hợp và tránh vòng lặp của indexOf và các hoạt động khác. jsperf.com/merge-two-arrays-keep-only-unique-values/21
slickplaid

"Băm" của bạn là String()chức năng trong javascript. Cái này có thể hoạt động cho các giá trị nguyên thủy (mặc dù có va chạm giữa các loại), nhưng nó không phù hợp với các mảng của các đối tượng.
Bergi

Tôi sử dụng một giải pháp tương tự, tôi cho phép chuyển một hàm hashCode hoặc truyền một chuỗi để xác định một thuộc tính trong đối tượng để sử dụng làm khóa băm.
Robert Baker

19

Chỉ cần tránh xa các vòng lặp lồng nhau (O (n ^ 2)) và .indexOf()(+ O (n)).

function merge(a, b) {
    var hash = {}, i;
    for (i=0; i<a.length; i++) {
        hash[a[i]]=true;
    } 
    for (i=0; i<b.length; i++) {
        hash[b[i]]=true;
    } 
    return Object.keys(hash);
}

2
Điều đó khá tuyệt vời, đặc biệt nếu bạn đang thực hiện các chuỗi. Các con số sẽ cần một bước bổ sung để giữ chúng như vậy. Hàm này hoàn toàn vượt qua tất cả các tùy chọn khác nếu bạn không quan tâm (hoặc quan tâm) rằng mọi thứ là một chuỗi sau khi bạn hoàn thành. Công việc tốt. Kết quả hoạt động tại đây: jsperf.com/merge-two-arrays-keep-only-unique-values/21
slickplaid

18

Đơn giản hóa tốt nhất câu trả lời này và biến nó thành một chức năng hay:

function mergeUnique(arr1, arr2){
    return arr1.concat(arr2.filter(function (item) {
        return arr1.indexOf(item) === -1;
    }));
}

2
Tôi tin rằng điều này là sạch sẽ hơn nhiều so với câu trả lời được chấp nhận. Ngoài ra, có vẻ như bộ lọc được hỗ trợ trong ECMAScript 5.1 +, hiện được hỗ trợ khá nhiều.
Tom Fobear

Điều này nên được chấp nhận
wallop

cái này ngắn gọn hơn nhiều
Mox

15

Tại sao bạn không sử dụng một đối tượng? Có vẻ như bạn đang cố gắng mô hình hóa một bộ. Điều này sẽ không bảo vệ trật tự, tuy nhiên.

var set1 = {"Vijendra":true, "Singh":true}
var set2 = {"Singh":true,  "Shakya":true}

// Merge second object into first
function merge(set1, set2){
  for (var key in set2){
    if (set2.hasOwnProperty(key))
      set1[key] = set2[key]
  }
  return set1
}

merge(set1, set2)

// Create set from array
function setify(array){
  var result = {}
  for (var item in array){
    if (array.hasOwnProperty(item))
      result[array[item]] = true
  }
  return result
}

Ý bạn là if (!set1.hasOwnProperty(key))sao?
Gumbo

2
Tại sao tôi có ý đó? Mục đích của điều kiện đó là bỏ qua các thuộc tính có thể có trong nguyên mẫu của đối tượng.
Nick Retallack

12

Giải pháp tốt nhất...

Bạn có thể kiểm tra trực tiếp trong bảng điều khiển trình duyệt bằng cách nhấn ...

Không trùng lặp

a = [1, 2, 3];
b = [3, 2, 1, "prince"];

a.concat(b.filter(function(el) {
    return a.indexOf(el) === -1;
}));

Với bản sao

["prince", "asish", 5].concat(["ravi", 4])

Nếu bạn muốn mà không bị trùng lặp, bạn có thể thử một giải pháp tốt hơn từ đây - Mã Shouting .

[1, 2, 3].concat([3, 2, 1, "prince"].filter(function(el) {
    return [1, 2, 3].indexOf(el) === -1;
}));

Thử trên bảng điều khiển trình duyệt Chrome

 f12 > console

Đầu ra:

["prince", "asish", 5, "ravi", 4]

[1, 2, 3, "prince"]

Nó không loại bỏ trùng lặp từ mảng đầu ra.
Shahar

9

Một xu rưỡi của tôi:

Array.prototype.concat_n_dedupe = function(other_array) {
  return this
    .concat(other_array) // add second
    .reduce(function(uniques, item) { // dedupe all
      if (uniques.indexOf(item) == -1) {
        uniques.push(item);
      }
      return uniques;
    }, []);
};

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var result = array1.concat_n_dedupe(array2);

console.log(result);

Nó không sử dụng bất cứ thứ gì mới trong ES6, tôi có bỏ lỡ điều gì không?
Bergi

@Bergi: Vâng, bạn nói đúng. Cảm ơn bạn đã lưu ý. Bằng cách nào đó tôi đã chơi với kịch bản này và có lẽ đã có một số phiên bản có chức năng ES6, nhưng bây giờ nó chứa indexOf đã có trong nhiều thế kỷ. Lỗi của tôi xin lỗi.
Anh hùng Qu

8

Bạn có thể đạt được nó chỉ bằng cách sử dụng Underscore.js's => uniq :

array3 = _.uniq(array1.concat(array2))

console.log(array3)

Nó sẽ in ["Vijendra", "Singh", "Shakya"] .



7

Tôi biết câu hỏi này không phải là về mảng các đối tượng, nhưng người tìm kiếm cuối cùng ở đây.

vì vậy, đáng để thêm cho độc giả tương lai một cách hợp nhất ES6 và sau đó loại bỏ trùng lặp

mảng đối tượng :

var arr1 = [ {a: 1}, {a: 2}, {a: 3} ];
var arr2 = [ {a: 1}, {a: 2}, {a: 4} ];

var arr3 = arr1.concat(arr2.filter( ({a}) => !arr1.find(f => f.a == a) ));

// [ {a: 1}, {a: 2}, {a: 3}, {a: 4} ]

6
//Array.indexOf was introduced in javascript 1.6 (ECMA-262) 
//We need to implement it explicitly for other browsers, 
if (!Array.prototype.indexOf)
{
  Array.prototype.indexOf = function(elt, from)
  {
    var len = this.length >>> 0;

    for (; from < len; from++)
    {
      if (from in this &&
          this[from] === elt)
        return from;
    }
    return -1;
  };
}
//now, on to the problem

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var merged = array1.concat(array2);
var t;
for(i = 0; i < merged.length; i++)
  if((t = merged.indexOf(i + 1, merged[i])) != -1)
  {
    merged.splice(t, 1);
    i--;//in case of multiple occurrences
  }

Việc thực hiện indexOfphương pháp cho các trình duyệt khác được lấy từ MDC


1
Tôi không thể tìm thấy nó trong w3schools, đó là lý do tại sao tôi viết nó. w3schools.com/jsref/jsref_obj_array.asp Nó có fromtham số btw không?
Amarghosh

Cảm ơn @Gumbo và @meder - sẽ thay đổi dấu trang của tôi ngay bây giờ. Tôi chưa làm gì nghiêm trọng trong js và tôi sử dụng w3school để tham khảo thông thường (đó là tất cả những gì tôi từng cần) - có thể đó là lý do tại sao tôi không nhận ra điều đó.
Amarghosh

MDC cho biết indexOf yêu cầu javascript 1.6 Liệu có an toàn không khi cho rằng các trình duyệt phổ biến (> = FF2,> IE6, v.v.) sẽ hỗ trợ nó?
Amarghosh

4
IE6 không hỗ trợ Array.prototype.indexOf, chỉ dán phương thức hỗ trợ do Mozilla cung cấp để IE không gây ra lỗi.
meder omuraliev

cập nhật bằng cách sử dụng indexOf. Làm sạch mã bằng cách loại bỏ phần bình luận. @meder - Cảm ơn một lần nữa.
Amarghosh

6

Giải pháp mới (sử dụng Array.prototype.indexOfArray.prototype.concat):

Array.prototype.uniqueMerge = function( a ) {
    for ( var nonDuplicates = [], i = 0, l = a.length; i<l; ++i ) {
        if ( this.indexOf( a[i] ) === -1 ) {
            nonDuplicates.push( a[i] );
        }
    }
    return this.concat( nonDuplicates )
};

Sử dụng:

>>> ['Vijendra', 'Singh'].uniqueMerge(['Singh', 'Shakya'])
["Vijendra", "Singh", "Shakya"]

Array.prototype.indexOf (dành cho trình thám hiểm internet):

Array.prototype.indexOf = Array.prototype.indexOf || function(elt)
  {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from): Math.floor(from); 
    if (from < 0)from += len;

    for (; from < len; from++)
    {
      if (from in this && this[from] === elt)return from;
    }
    return -1;
  };

@Mender: nếu đơn hàng không thành vấn đề thì tôi phải làm thế nào
Vijjendra

1
Đây không phải là một phương thức ECMAScript tiêu chuẩn được xác định cho Array.prototype, mặc dù tôi biết rằng bạn có thể dễ dàng xác định nó cho IE và các trình duyệt khác không hỗ trợ nó.
trung gian ometiciev

Lưu ý rằng thuật toán này là O (n ^ 2).
Gumbo

Thuật toán nào là câu trả lời của bạn?
meder omuraliev

@meder: Thuật toán của tôi là thuật toán hợp. Liên minh được thực hiện trong O (n + m), nhưng việc sắp xếp mất nhiều nhất là O (n · log n + m · log m). Vậy toàn bộ thuật toán là O (n · log n + m · log m).
Gumbo

6

Nó có thể được thực hiện bằng cách sử dụng Set.

var array1 = ["Vijendra","Singh"];
var array2 = ["Singh", "Shakya"];

var array3 = array1.concat(array2);
var tempSet = new Set(array3);
array3 = Array.from(tempSet);

//show output
document.body.querySelector("div").innerHTML = JSON.stringify(array3);
<div style="width:100%;height:4rem;line-height:4rem;background-color:steelblue;color:#DDD;text-align:center;font-family:Calibri" > 
  temp text 
</div>


6

Có rất nhiều giải pháp để hợp nhất hai mảng. Chúng có thể được chia thành hai loại chính (ngoại trừ việc sử dụng các thư viện của bên thứ 3 như lodash hoặc underscore.js).

a) kết hợp hai mảng và loại bỏ các mục trùng lặp.

b) lọc các mục trước khi kết hợp chúng.

Kết hợp hai mảng và loại bỏ các mục trùng lặp

Kết hợp

// mutable operation(array1 is the combined array)
array1.push(...array2);
array1.unshift(...array2);

// immutable operation
const combined = array1.concat(array2);
const combined = [...array1, ...array2];    // ES6

Thống nhất

Có nhiều cách để thống nhất một mảng, cá nhân tôi đề xuất dưới đây hai phương pháp.

// a little bit tricky
const merged = combined.filter((item, index) => combined.indexOf(item) === index);
const merged = [...new Set(combined)];

Lọc ra các mục trước khi kết hợp chúng

Cũng có nhiều cách, nhưng cá nhân tôi đề xuất mã dưới đây do tính đơn giản của nó.

const merged = array1.concat(array2.filter(secItem => !array1.includes(secItem)));

5
Array.prototype.add = function(b){
    var a = this.concat();                // clone current object
    if(!b.push || !b.length) return a;    // if b is not an array, or empty, then return a unchanged
    if(!a.length) return b.concat();      // if original is empty, return b

    // go through all the elements of b
    for(var i = 0; i < b.length; i++){
        // if b's value is not in a, then add it
        if(a.indexOf(b[i]) == -1) a.push(b[i]);
    }
    return a;
}

// Example:
console.log([1,2,3].add([3, 4, 5])); // will output [1, 2, 3, 4, 5]

5
array1.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)

Điểm hay của cái này là hiệu năng và nói chung, khi bạn làm việc với mảng, là các phương thức xâu chuỗi như bộ lọc, bản đồ, v.v. để bạn có thể thêm dòng đó và nó sẽ nối và sao chép mảng2 với mảng1 mà không cần tham chiếu đến phần sau một (khi bạn đang xâu chuỗi các phương thức bạn không có), ví dụ:

someSource()
.reduce(...)
.filter(...)
.map(...) 
// and now you want to concat array2 and deduplicate:
.concat(array2).filter((value, pos, arr)=>arr.indexOf(value)===pos)
// and keep chaining stuff
.map(...)
.find(...)
// etc

(Tôi không muốn làm ô nhiễm Array.prototype và đó sẽ là cách duy nhất để tôn trọng chuỗi - xác định một hàm mới sẽ phá vỡ nó - vì vậy tôi nghĩ rằng một cái gì đó như thế này là cách duy nhất để thực hiện điều đó)


4

Bạn có thể thử điều này:

const union = (a, b) => Array.from(new Set([...a, ...b]));

console.log(union(["neymar","messi"], ["ronaldo","neymar"]));


3

Một cách tiếp cận chức năng với ES2015

Theo cách tiếp cận chức năng, một uniontrong hai Arrays chỉ là thành phần của concatfilter. Để cung cấp hiệu suất tối ưu, chúng tôi sử dụng Setkiểu dữ liệu gốc , được tối ưu hóa cho tra cứu thuộc tính.

Dù sao, câu hỏi quan trọng kết hợp với một unionchức năng là làm thế nào để điều trị trùng lặp. Các hoán vị sau đây là có thể:

Array A      + Array B

[unique]     + [unique]
[duplicated] + [unique]
[unique]     + [duplicated]
[duplicated] + [duplicated]

Hai hoán vị đầu tiên rất dễ xử lý với một chức năng duy nhất. Tuy nhiên, hai cái cuối phức tạp hơn, vì bạn không thể xử lý chúng miễn là bạn dựa vào Settra cứu. Kể từ khi chuyển sang Objecttra cứu tài sản cũ đơn giản sẽ đòi hỏi một hiệu suất nghiêm trọng đạt được việc thực hiện sau đây chỉ cần bỏ qua hoán vị thứ ba và thứ tư. Bạn sẽ phải xây dựng một phiên bản riêng unionđể hỗ trợ họ.


// small, reusable auxiliary functions

const comp = f => g => x => f(g(x));
const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const afrom = apply(Array.from);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// de-duplication

const dedupe = comp(afrom) (createSet);


// the actual union function

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];


// here we go

console.log( "unique/unique", union(dedupe(xs)) (ys) );
console.log( "duplicated/unique", union(xs) (ys) );

Từ đây trở đi tầm thường để thực hiện một unionnhàm, chấp nhận bất kỳ số lượng mảng nào (lấy cảm hứng từ các bình luận của naomik):

// small, reusable auxiliary functions

const uncurry = f => (a, b) => f(a) (b);
const foldl = f => acc => xs => xs.reduce(uncurry(f), acc);

const apply = f => a => f(a);
const flip = f => b => a => f(a) (b);
const concat = xs => y => xs.concat(y);
const createSet = xs => new Set(xs);
const filter = f => xs => xs.filter(apply(f));


// union and unionn

const union = xs => ys => {
  const zs = createSet(xs);  
  return concat(xs) (
    filter(x => zs.has(x)
     ? false
     : zs.add(x)
  ) (ys));
}

const unionn = (head, ...tail) => foldl(union) (head) (tail);


// mock data

const xs = [1,2,2,3,4,5];
const ys = [0,1,2,3,3,4,5,6,6];
const zs = [0,1,2,3,4,5,6,7,8,9];


// here we go

console.log( unionn(xs, ys, zs) );

Hóa ra unionnchỉ là foldl(aka Array.prototype.reduce), lấy unionlàm giảm tốc của nó. Lưu ý: Vì việc triển khai không sử dụng bộ tích lũy bổ sung, nó sẽ gây ra lỗi khi bạn áp dụng nó mà không có đối số.


1
Một vài phản hồi: Tôi nhận thấy điều đó flipnotfkhông được sử dụng. Cũng unionBydự đoán chi tiết thực hiện rò rỉ (đòi hỏi kiến ​​thức ngầm về Setloại). Nó có thể tốt nếu bạn có thể làm một cái gì đó như thế này: union = unionBy (apply)unionci = unionBy (p => x => p(x.toLowerCase())). Bằng cách đó, người dùng chỉ cần gửi bất kỳ giá trị nhóm nào đến p- chỉ là một ý tưởng ^ _ ^
Cảm ơn bạn

zskhai báo biến cũng thiếu var/ lettừ khóa
Cảm ơn bạn

1
đây là đoạn mã để làm rõ [ý chính: unionBy.js ]
Cảm ơn bạn

@naomik Sau khi suy nghĩ lại về giải pháp của tôi trong một thời gian, tôi không còn chắc chắn nữa nếu đó là cách đúng để vượt qua vị ngữ. Tất cả những gì bạn đạt được là một phép biến đổi của từng phần tử của mảng thứ hai. Tôi tự hỏi nếu phương pháp này giải quyết nhiều hơn chỉ là vấn đề đồ chơi.

3

vì lợi ích của nó ... đây là một giải pháp dòng duy nhất:

const x = [...new Set([['C', 'B'],['B', 'A']].reduce( (a, e) => a.concat(e), []))].sort()
// ['A', 'B', 'C']

Không đặc biệt dễ đọc nhưng nó có thể giúp ai đó:

  1. Áp dụng hàm giảm với giá trị bộ tích lũy ban đầu được đặt thành một mảng trống.
  2. Hàm less sử dụng concat để nối từng mảng con vào mảng tích lũy.
  3. Kết quả của điều này được thông qua dưới dạng tham số constructor để tạo mới Set.
  4. Toán tử trải được sử dụng để chuyển đổi Setthành một mảng.
  5. Các sort() chức năng được áp dụng cho mảng mới.

2
Ngoài ra, thay vì reduce()bạn có thể sử dụngArray.from(set)
Eran Goldin

3

Khử trùng lặp đơn hoặc Hợp nhất và Hủy lặp lại nhiều đầu vào mảng. Ví dụ dưới đây.

sử dụng ES6 - Đặt, cho, phá hủy

Tôi đã viết hàm đơn giản này có nhiều đối số mảng. Có khá nhiều giống như giải pháp ở trên nó chỉ có trường hợp sử dụng thực tế hơn. Hàm này không nối các giá trị trùng lặp thành một mảng để nó có thể xóa chúng ở giai đoạn sau.

ĐỊNH NGH DEA CHỨC NĂNG NGẮN HẠN (chỉ có 9 dòng)

/**
* This function merging only arrays unique values. It does not merges arrays in to array with duplicate values at any stage.
*
* @params ...args Function accept multiple array input (merges them to single array with no duplicates)
* it also can be used to filter duplicates in single array
*/
function arrayDeDuplicate(...args){
   let set = new Set(); // init Set object (available as of ES6)
   for(let arr of args){ // for of loops through values
      arr.map((value) => { // map adds each value to Set object
         set.add(value); // set.add method adds only unique values
      });
   }
   return [...set]; // destructuring set object back to array object
   // alternativly we culd use:  return Array.from(set);
}

SỬ DỤNG VÍ DỤ CODEPEN :

// SCENARIO 
let a = [1,2,3,4,5,6];
let b = [4,5,6,7,8,9,10,10,10];
let c = [43,23,1,2,3];
let d = ['a','b','c','d'];
let e = ['b','c','d','e'];

// USEAGE
let uniqueArrayAll = arrayDeDuplicate(a, b, c, d, e);
let uniqueArraySingle = arrayDeDuplicate(b);

// OUTPUT
console.log(uniqueArrayAll); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 43, 23, "a", "b", "c", "d", "e"]
console.log(uniqueArraySingle); // [4, 5, 6, 7, 8, 9, 10]

Tại sao sử dụng arr.mapở đây? Bạn đang sử dụng nó như một foreachkết quả bị bỏ qua
Antony

Tôi đã sử dụng return Array.from (set.values ​​()); , vì vscode đưa ra lỗi khi trả về [... set];
makkasi

3
var arr1 = [1, 3, 5, 6];
var arr2 = [3, 6, 10, 11, 12];
arr1.concat(arr2.filter(ele => !arr1.includes(ele)));
console.log(arr1);

output :- [1, 3, 5, 6, 10, 11, 12]

3

var array1 = ["one","two"];
var array2 = ["two", "three"];
var collectionOfTwoArrays = [...array1, ...array2];    
var uniqueList = array => [...new Set(array)];
console.log('Collection :');
console.log(collectionOfTwoArrays);    
console.log('Collection without duplicates :');
console.log(uniqueList(collectionOfTwoArrays));

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.