Làm thế nào để so sánh các mảng trong JavaScript?


988

Tôi muốn so sánh hai mảng ... lý tưởng, hiệu quả. Không có gì lạ mắt, chỉ cần truechúng giống hệt nhau, và falsenếu không. Không có gì đáng ngạc nhiên, toán tử so sánh dường như không hoạt động.

var a1 = [1,2,3];
var a2 = [1,2,3];
console.log(a1==a2);    // Returns false
console.log(JSON.stringify(a1)==JSON.stringify(a2));    // Returns true

JSON mã hóa từng mảng, nhưng có cách nào nhanh hơn hoặc "tốt hơn" để đơn giản so sánh các mảng mà không phải lặp qua từng giá trị?


5
Trước tiên, bạn có thể so sánh độ dài của chúng và nếu chúng bằng nhau từng giá trị.
TJHeuvel

55
Điều gì làm cho hai mảng bằng nhau cho bạn? Các yếu tố giống nhau? Cùng thứ tự các yếu tố? Mã hóa dưới dạng JSON chỉ hoạt động miễn là phần tử của mảng có thể được tuần tự hóa thành JSON. Nếu mảng có thể chứa các đối tượng, bạn sẽ đi sâu đến đâu? Khi nào hai đối tượng "bằng nhau"?
Felix Kling

48
@FelixKling, định nghĩa "bình đẳng" chắc chắn là một chủ đề tinh tế, nhưng đối với những người đến với JavaScript từ các ngôn ngữ cấp cao hơn, không có lý do gì cho sự điên cuồng như thế nào ([] == []) == false.
Alex D

4
@AlexD có vẻ như các mảng sử dụng đẳng thức tham chiếu là những gì bạn mong đợi. Sẽ rất tệ nếu bạn không thể làm điều đó
JonnyRaa

3
@AlexD Tôi phần nào không thể nghĩ ra một ngôn ngữ mà điều này không xảy ra. Trong C ++, bạn sẽ so sánh hai con trỏ - sai. Trong Java, bạn đang làm giống như trong javascript. Trong PHP, một cái gì đó đằng sau hậu trường sẽ lặp qua các mảng - bạn có gọi PHP là ngôn ngữ cấp cao hơn không?
Tomáš Zato - Tái lập lại

Câu trả lời:


877

Để so sánh các mảng, lặp qua chúng và so sánh mọi giá trị:

So sánh mảng:

// Warn if overriding existing method
if(Array.prototype.equals)
    console.warn("Overriding existing Array.prototype.equals. Possible causes: New API defines the method, there's a framework conflict or you've got double inclusions in your code.");
// attach the .equals method to Array's prototype to call it on any array
Array.prototype.equals = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time 
    if (this.length != array.length)
        return false;

    for (var i = 0, l=this.length; i < l; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].equals(array[i]))
                return false;       
        }           
        else if (this[i] != array[i]) { 
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;   
        }           
    }       
    return true;
}
// Hide method from for-in loops
Object.defineProperty(Array.prototype, "equals", {enumerable: false});

Sử dụng:

[1, 2, [3, 4]].equals([1, 2, [3, 2]]) === false;
[1, "2,3"].equals([1, 2, 3]) === false;
[1, 2, [3, 4]].equals([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].equals([1, 2, 1, 2]) === true;

Bạn có thể nói " Nhưng nhanh hơn nhiều so với các chuỗi - không có vòng lặp ... ", thì bạn nên lưu ý có các vòng lặp. Vòng lặp đệ quy đầu tiên chuyển đổi Array thành chuỗi và thứ hai, so sánh hai chuỗi. Vì vậy, phương pháp này nhanh hơn sử dụng chuỗi .

Tôi tin rằng lượng dữ liệu lớn hơn phải luôn được lưu trữ trong mảng chứ không phải trong các đối tượng. Tuy nhiên nếu bạn sử dụng các đối tượng, chúng cũng có thể được so sánh một phần.
Đây là cách thực hiện:

Đối tượng so sánh:

Tôi đã nói ở trên, hai trường hợp đối tượng sẽ không bao giờ bằng nhau, ngay cả khi chúng chứa cùng một dữ liệu tại thời điểm này:

({a:1, foo:"bar", numberOfTheBeast: 666}) == ({a:1, foo:"bar", numberOfTheBeast: 666})  //false

Điều này có một lý do, vì có thể có, ví dụ các biến riêng tư trong các đối tượng.

Tuy nhiên, nếu bạn chỉ sử dụng cấu trúc đối tượng để chứa dữ liệu, vẫn có thể so sánh:

Object.prototype.equals = function(object2) {
    //For the first loop, we only check for types
    for (propName in this) {
        //Check for inherited methods and properties - like .equals itself
        //https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
        //Return false if the return value is different
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        //Check instance type
        else if (typeof this[propName] != typeof object2[propName]) {
            //Different types => not equal
            return false;
        }
    }
    //Now a deeper check using other objects property names
    for(propName in object2) {
        //We must check instances anyway, there may be a property that only exists in object2
            //I wonder, if remembering the checked values from the first loop would be faster or not 
        if (this.hasOwnProperty(propName) != object2.hasOwnProperty(propName)) {
            return false;
        }
        else if (typeof this[propName] != typeof object2[propName]) {
            return false;
        }
        //If the property is inherited, do not check any more (it must be equa if both objects inherit it)
        if(!this.hasOwnProperty(propName))
          continue;

        //Now the detail check and recursion

        //This returns the script back to the array comparing
        /**REQUIRES Array.equals**/
        if (this[propName] instanceof Array && object2[propName] instanceof Array) {
                   // recurse into the nested arrays
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        else if (this[propName] instanceof Object && object2[propName] instanceof Object) {
                   // recurse into another objects
                   //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
           if (!this[propName].equals(object2[propName]))
                        return false;
        }
        //Normal value comparison for strings and numbers
        else if(this[propName] != object2[propName]) {
           return false;
        }
    }
    //If everything passed, let's say YES
    return true;
}  

Tuy nhiên, hãy nhớ rằng cái này là để phục vụ trong việc so sánh JSON như dữ liệu, không phải các thể hiện lớp và các thứ khác. Nếu bạn muốn so sánh các đối tượng phức tạp mor, hãy xem câu trả lời này và đó là chức năng siêu dài .
Để thực hiện công việc này với Array.equalsbạn, bạn phải chỉnh sửa chức năng ban đầu một chút:

...
    // Check if we have nested arrays
    if (this[i] instanceof Array && array[i] instanceof Array) {
        // recurse into the nested arrays
        if (!this[i].equals(array[i]))
            return false;
    }
    /**REQUIRES OBJECT COMPARE**/
    else if (this[i] instanceof Object && array[i] instanceof Object) {
        // recurse into another objects
        //console.log("Recursing to compare ", this[propName],"with",object2[propName], " both named \""+propName+"\"");
        if (!this[i].equals(array[i]))
            return false;
        }
    else if (this[i] != array[i]) {
...

Tôi đã tạo ra một công cụ kiểm tra nhỏ cho cả hai chức năng .

Phần thưởng: Mảng lồng nhau với indexOfcontains

Samy Bencherif đã chuẩn bị các chức năng hữu ích cho trường hợp bạn đang tìm kiếm một đối tượng cụ thể trong các mảng lồng nhau, có sẵn ở đây: https://jsfiddle.net/SamyBencherif/8352y6yw/


27
Nếu bạn muốn làm so sánh nghiêm ngặt sử dụng this[i] !== array[i]thay vì !=.
Tim S.

38
Phương pháp của bạn nên được gọi equalsthay vì compare. Ít nhất là trong .NET, so sánh thường trả về một int đã ký cho biết đối tượng nào lớn hơn đối tượng khác. Xem: So sánh.Compare .
Oliver

15
Đây chỉ là cách làm đúng đắn, nó cũng hiệu quả hơn đáng kể. Đây là một kịch bản jsperf nhanh chóng mà tôi đã chuẩn bị cho tất cả các phương pháp được đề xuất trong câu hỏi này. jsperf.com/compared-arrays2
Tolga E

96
Thay đổi nguyên mẫu của loại tích hợp chắc chắn không phải là cách đúng đắn
Jasper

31
Bên cạnh đó, không phải là nó có dễ viết lại hay không, mà thực tế là một câu trả lời không nên đề xuất một thứ được coi là thực hành xấu ( developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/ tựa ) và nên chắc chắn không làm điều này dưới tiêu đề "Đúng cách"
Jasper

386

Mặc dù điều này chỉ hoạt động cho các mảng vô hướng (xem ghi chú bên dưới), nhưng nó ngắn:

array1.length === array2.length && array1.every(function(value, index) { return value === array2[index]})

Rr, trong ECMAScript 6 / CoffeeScript / TypeScript với các hàm mũi tên:

array1.length === array2.length && array1.every((value, index) => value === array2[index])

(Lưu ý: 'vô hướng' ở đây có nghĩa là các giá trị có thể được so sánh trực tiếp bằng cách sử dụng ===. Vì vậy: số, chuỗi, đối tượng theo tham chiếu, hàm theo tham chiếu. Xem tham chiếu MDN để biết thêm thông tin về toán tử so sánh).

CẬP NHẬT

Từ những gì tôi đọc được từ các bình luận, sắp xếp mảng và so sánh có thể cho kết quả chính xác:

array1.length === array2.length && array1.sort().every(function(value, index) { return value === array2.sort()[index]});

Ví dụ:

array1 = [2,3,1,4];
array2 = [1,2,3,4];

Sau đó, mã trên sẽ cung cấp cho true


19
Tôi thích điều này, mặc dù độc giả nên biết điều này chỉ hoạt động trên các mảng được sắp xếp.
Ellen Spertus

13
Nó hoạt động trên bất kỳ loại mảng nào, được sắp xếp hoặc không @espertus
Michał Miszczyszyn

36
Đúng chính xác. Hàm này được cho là so sánh hai mảng, không quan trọng chúng có được sắp xếp hay không, các phần tử liên tiếp của chúng phải bằng nhau.
Michał Miszczyszyn

22
@espertus Thật vậy, nó sẽ không trở lại đúng nếu các phần tử không có cùng thứ tự chính xác trong cả hai mảng. Tuy nhiên, mục tiêu của kiểm tra đẳng thức không phải là kiểm tra xem chúng có chứa các phần tử giống nhau hay không mà là kiểm tra xem chúng có cùng phần tử trong cùng một đơn đặt hàng hay không.
Quentin Roy

7
Nếu bạn muốn kiểm tra xem cả hai mảng có bằng nhau không, có chứa các mục chưa được sắp xếp giống nhau (nhưng không được sử dụng nhiều lần), bạn có thể sử dụng a1.length==a2.length && a1.every((v,i)=>a2.includes(v)): var a1 =[1,2,3], a2 = [3,2,1];( var a1 =[1,3,3], a2 = [1,1,3];sẽ không hoạt động như mong đợi)
mems

208

Tôi thích sử dụng thư viện Underscore cho các dự án mã hóa mảng / đối tượng nặng ... trong Underscore và Lodash cho dù bạn đang so sánh các mảng hoặc các đối tượng giống như thế này:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean

22
Lưu ý rằng vấn đề đặt hàng _.isEqual([1,2,3], [2,1,3]) => false
Vitaliy Alekask 18/08/2015

3
hoặc nếu bạn chỉ muốn isEqualchức năng, bạn luôn có thể sử dụng mô-đun
lodash.isequal

6
Bạn có thể sử dụng _.difference (); nếu đơn hàng không quan trọng với bạn
Ronan Quillevere

5
Chúng tôi có thể sắp xếp mảng trước kiểm tra này nếu thứ tự không thành vấn đề_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Filype

Câu trả lời ngắn gọn và thẳng thắn nhất IMHO :-)
Kieran Ryan

121

Tôi nghĩ đây là cách đơn giản nhất để thực hiện bằng cách sử dụng JSON Stringify và nó có thể là giải pháp tốt nhất trong một số trường hợp:

JSON.stringify(a1) === JSON.stringify(a2);

Điều này chuyển đổi các đối tượng a1a2thành chuỗi để chúng có thể được so sánh. Thứ tự này rất quan trọng trong hầu hết các trường hợp, vì điều đó có thể sắp xếp đối tượng bằng thuật toán sắp xếp được hiển thị trong một trong các câu trả lời ở trên.

Xin lưu ý rằng bạn không còn so sánh đối tượng mà là biểu diễn chuỗi của đối tượng. Nó có thể không chính xác những gì bạn muốn.


câu trả lời tốt nhưng tại sao [] == [] trả về sai? Cả hai đều là những đối tượng đơn giản thì tại sao?
Pardeep Jain

4
@PardeepJain, điều này là do theo mặc định, toán tử đẳng thức trong ECMAScript cho các đối tượng trả về true khi chúng tham chiếu cùng một vị trí bộ nhớ. Hãy thử var x = y = []; // bây giờ đẳng thức trả về true.
radtek

7
chỉ cần lưu ý rằng hàm JSONify không nhanh chóng. Được sử dụng với các mảng lớn hơn chắc chắn sẽ giới thiệu độ trễ.
Lukas Liesis

6
Câu hỏi đặc biệt hỏi liệu có cách nào tốt hơn / nhanh hơn so với sử dụng JSON.opesify.
Don nở

Nó đi vào chi tiết hơn về lý do tại sao điều này có thể là một giải pháp tốt cho một số tình huống.
radtek

61

Không rõ ý của bạn là "giống hệt". Ví dụ, các mảng abbên dưới có giống nhau không (lưu ý các mảng lồng nhau)?

var a = ["foo", ["bar"]], b = ["foo", ["bar"]];

Đây là một hàm so sánh mảng được tối ưu hóa, lần lượt so sánh các phần tử tương ứng của từng mảng bằng cách sử dụng đẳng thức nghiêm ngặt và không so sánh đệ quy các phần tử mảng mà chính chúng là mảng, có nghĩa là ví dụ trên arraysIdentical(a, b)sẽ trả về false. Nó hoạt động trong trường hợp chung, mà join()các giải pháp dựa trên JSON và sẽ không:

function arraysIdentical(a, b) {
    var i = a.length;
    if (i != b.length) return false;
    while (i--) {
        if (a[i] !== b[i]) return false;
    }
    return true;
};

@ASDF: Không rõ từ câu hỏi "giống hệt" nghĩa là gì. Rõ ràng câu trả lời này chỉ là một kiểm tra nông. Tôi sẽ thêm một ghi chú.
Tim Down

điều này không thành công cho mảngIdentical ([1, 2, [3, 2]], [1, 2, [3, 2]]);
Gopinath Shiva

4
@GopinathShiva: Chà, nó chỉ thất bại nếu bạn mong đợi nó trở lại true. Câu trả lời giải thích rằng nó sẽ không. Nếu bạn cần so sánh các mảng lồng nhau, bạn có thể dễ dàng thêm kiểm tra đệ quy.
Tim Down

59

Cách thực hành

Tôi nghĩ thật sai lầm khi nói một triển khai cụ thể là "Đúng cách ™" nếu chỉ "đúng" ("đúng") trái ngược với giải pháp "sai". Giải pháp của Tomáš là một cải tiến rõ ràng so với so sánh mảng dựa trên chuỗi, nhưng điều đó không có nghĩa là nó "đúng" một cách khách quan. Điều gì là đúng ? Có phải là nhanh nhất? Nó có linh hoạt nhất không? Là nó dễ hiểu nhất? Đây có phải là cách nhanh nhất để gỡ lỗi? Nó sử dụng ít hoạt động nhất? Nó có bất kỳ tác dụng phụ? Không một giải pháp nào có thể có thứ tốt nhất trong tất cả mọi thứ.

Tomáš có thể nói giải pháp của anh ấy rất nhanh nhưng tôi cũng sẽ nói rằng nó rất phức tạp. Nó cố gắng trở thành một giải pháp tất cả trong một, hoạt động cho tất cả các mảng, lồng nhau hoặc không. Trên thực tế, nó thậm chí còn chấp nhận nhiều hơn là các mảng như một đầu vào và vẫn cố gắng đưa ra câu trả lời "hợp lệ".


Generics cung cấp tái sử dụng

Câu trả lời của tôi sẽ tiếp cận vấn đề khác nhau. Tôi sẽ bắt đầu với một arrayComparethủ tục chung chỉ liên quan đến việc bước qua các mảng. Từ đó, chúng tôi sẽ xây dựng chức năng so sánh cơ bản khác của chúng tôi như arrayEqualarrayDeepEqual, vv

// arrayCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayCompare = f => ([x,...xs]) => ([y,...ys]) =>
  x === undefined && y === undefined
    ? true
    : Boolean (f (x) (y)) && arrayCompare (f) (xs) (ys)

Theo tôi, loại mã tốt nhất thậm chí không cần bình luận, và điều này cũng không ngoại lệ. Có quá ít xảy ra ở đây mà bạn có thể hiểu hành vi của thủ tục này mà hầu như không có nỗ lực nào cả. Chắc chắn, một số cú pháp ES6 có vẻ xa lạ với bạn bây giờ, nhưng đó chỉ là do ES6 còn khá mới.

Như kiểu gợi ý, arrayComparecó chức năng so sánh f, và hai mảng đầu vào, xsys. Đối với hầu hết các phần, tất cả những gì chúng ta làm là gọi f (x) (y)cho từng phần tử trong mảng đầu vào. Chúng tôi trở lại một đầu falsenếu người dùng xác định flợi nhuận false- nhờ &&'s đánh giá ngắn mạch. Vì vậy, có, điều này có nghĩa là bộ so sánh có thể dừng lặp lại sớm và ngăn chặn việc lặp qua phần còn lại của mảng đầu vào khi không cần thiết.


So sánh nghiêm ngặt

Tiếp theo, sử dụng arrayComparechức năng của chúng tôi , chúng tôi có thể dễ dàng tạo các chức năng khác mà chúng tôi có thể cần. Chúng tôi sẽ bắt đầu với tiểu arrayEqual...

// equal :: a -> a -> Bool
const equal = x => y =>
  x === y // notice: triple equal

// arrayEqual :: [a] -> [a] -> Bool
const arrayEqual =
  arrayCompare (equal)

const xs = [1,2,3]
const ys = [1,2,3]
console.log (arrayEqual (xs) (ys))      //=> true
// (1 === 1) && (2 === 2) && (3 === 3)  //=> true

const zs = ['1','2','3']
console.log (arrayEqual (xs) (zs))      //=> false
// (1 === '1')                          //=> false

Đơn giản như thế. arrayEqualcó thể được định nghĩa với arrayComparevà một hàm so sánh so sánh avới bviệc sử dụng ===(đối với đẳng thức nghiêm ngặt).

Lưu ý rằng chúng tôi cũng định nghĩa equallà chức năng riêng của nó. Điều này nhấn mạnh vai trò của arrayComparemột hàm bậc cao hơn để sử dụng bộ so sánh thứ tự đầu tiên của chúng tôi trong bối cảnh của một loại dữ liệu khác (Mảng).


So sánh lỏng lẻo

Chúng ta có thể dễ dàng xác định arrayLooseEqualbằng cách sử dụng ==thay thế. Bây giờ khi so sánh 1(Số) để '1'(String), kết quả sẽ là true...

// looseEqual :: a -> a -> Bool
const looseEqual = x => y =>
  x == y // notice: double equal

// arrayLooseEqual :: [a] -> [a] -> Bool
const arrayLooseEqual =
  arrayCompare (looseEqual)

const xs = [1,2,3]
const ys = ['1','2','3']
console.log (arrayLooseEqual (xs) (ys))    //=> true
// (1 == '1') && (2 == '2') && (3 == '3')  //=> true

So sánh sâu (đệ quy)

Bạn có thể nhận thấy rằng đây chỉ là so sánh nông. Chắc chắn giải pháp của Tomáš là "The Right Way ™" bởi vì nó ngầm ẩn sự so sánh sâu sắc, phải không?

Chà, arrayComparethủ tục của chúng tôi đủ linh hoạt để sử dụng theo cách làm cho một bài kiểm tra công bằng sâu sắc trở nên dễ dàng

// isArray :: a -> Bool
const isArray =
  Array.isArray

// arrayDeepCompare :: (a -> a -> Bool) -> [a] -> [a] -> Bool
const arrayDeepCompare = f =>
  arrayCompare (a => b =>
    isArray (a) && isArray (b)
      ? arrayDeepCompare (f) (a) (b)
      : f (a) (b))

const xs = [1,[2,[3]]]
const ys = [1,[2,['3']]]
console.log (arrayDeepCompare (equal) (xs) (ys)) //=> false
// (1 === 1) && (2 === 2) && (3 === '3')         //=> false

console.log (arrayDeepCompare (looseEqual) (xs) (ys)) //=> true
// (1 == 1) && (2 == 2) && (3 == '3')                 //=> true

Đơn giản như thế. Chúng tôi xây dựng một bộ so sánh sâu bằng cách sử dụng chức năng bậc cao khác . Lần này chúng tôi sẽ arrayComparesử dụng một bộ so sánh tùy chỉnh sẽ kiểm tra xem abcó phải là mảng không. Nếu vậy, hãy áp dụng lại arrayDeepCompareso sánh avà so sánh với bộ so sánh bdo người dùng chỉ định ( f). Điều này cho phép chúng tôi giữ hành vi so sánh sâu tách biệt với cách chúng tôi thực sự so sánh các yếu tố riêng lẻ. Ví dụ, như ví dụ trên cho thấy, chúng ta có thể so sánh sâu sử dụng equal, looseEqualhoặc bất kỳ so sánh khác mà chúng tôi thực hiện.

arrayDeepComparebị chế giễu, chúng ta có thể áp dụng một phần như trong các ví dụ trước

// arrayDeepEqual :: [a] -> [a] -> Bool
const arrayDeepEqual =
  arrayDeepCompare (equal)

// arrayDeepLooseEqual :: [a] -> [a] -> Bool
const arrayDeepLooseEqual =
  arrayDeepCompare (looseEqual)

Đối với tôi, đây đã là một cải tiến rõ ràng so với giải pháp của Tomáš vì tôi rõ ràng có thể chọn một so sánh nông hoặc sâu cho các mảng của mình, khi cần.


So sánh đối tượng (ví dụ)

Bây giờ nếu bạn có một mảng các đối tượng hoặc một cái gì đó thì sao? Có lẽ bạn muốn coi các mảng đó là "bằng nhau" nếu mỗi đối tượng có cùng idgiá trị

// idEqual :: {id: Number} -> {id: Number} -> Bool
const idEqual = x => y =>
  x.id !== undefined && x.id === y.id

// arrayIdEqual :: [a] -> [a] -> Bool
const arrayIdEqual =
  arrayCompare (idEqual)

const xs = [{id:1}, {id:2}]
const ys = [{id:1}, {id:2}]
console.log (arrayIdEqual (xs) (ys)) //=> true
// (1 === 1) && (2 === 2)            //=> true

const zs = [{id:1}, {id:6}]
console.log (arrayIdEqual (xs) (zs)) //=> false
// (1 === 1) && (2 === 6)            //=> false

Đơn giản như thế. Ở đây tôi đã sử dụng các đối tượng JS vanilla, nhưng loại so sánh này có thể hoạt động cho bất kỳ loại đối tượng nào ; thậm chí các đối tượng tùy chỉnh của bạn. Giải pháp của Tomáš sẽ cần phải được làm lại hoàn toàn để hỗ trợ loại thử nghiệm bình đẳng này

Mảng sâu với các đối tượng? Không thành vấn đề. Chúng tôi đã xây dựng các chức năng chung, linh hoạt cao, vì vậy chúng sẽ hoạt động trong nhiều trường hợp sử dụng khác nhau.

const xs = [{id:1}, [{id:2}]]
const ys = [{id:1}, [{id:2}]]
console.log (arrayCompare (idEqual) (xs) (ys))     //=> false
console.log (arrayDeepCompare (idEqual) (xs) (ys)) //=> true

So sánh tùy tiện (ví dụ)

Hoặc nếu bạn muốn làm một số loại so sánh hoàn toàn tùy ý khác thì sao? Có lẽ tôi muốn biết nếu mỗi cái xlớn hơn mỗi tên ylửa

// gt :: Number -> Number -> Bool
const gt = x => y =>
  x > y

// arrayGt :: [a] -> [a] -> Bool
const arrayGt = arrayCompare (gt)

const xs = [5,10,20]
const ys = [2,4,8]
console.log (arrayGt (xs) (ys))     //=> true
// (5 > 2) && (10 > 4) && (20 > 8)  //=> true

const zs = [6,12,24]
console.log (arrayGt (xs) (zs))     //=> false
// (5 > 6)                          //=> false

Càng đơn giản càng đẹp

Bạn có thể thấy chúng tôi thực sự đang làm nhiều hơn với ít mã hơn. Không có gì phức tạp về arrayComparebản thân và mỗi bộ so sánh tùy chỉnh chúng tôi đã thực hiện có một cách thực hiện rất đơn giản.

Để dễ dàng, chúng ta có thể xác định chính xác cách chúng ta muốn so sánh hai mảng - nông, sâu, nghiêm ngặt, lỏng lẻo, một số thuộc tính đối tượng hoặc một số tính toán tùy ý hoặc bất kỳ kết hợp nào của các mảng - tất cả đều sử dụng một thủ tục , arrayCompare. Thậm chí có thể mơ lên ​​một RegExpso sánh! Tôi biết trẻ em thích những trò regexps như thế nào

Có phải là nhanh nhất? Không. Nhưng nó có lẽ không cần phải là một trong hai. Nếu tốc độ là chỉ số duy nhất được sử dụng để đo lường chất lượng mã của chúng tôi, thì rất nhiều mã thực sự tuyệt vời sẽ bị loại bỏ - Đó là lý do tại sao tôi gọi phương pháp này là Cách thực tế . Hoặc có thể để công bằng hơn, Một cách thực tế. Mô tả này phù hợp với câu trả lời này vì tôi không nói câu trả lời này chỉ thực tế so với một số câu trả lời khác; nó là khách quan đúng Chúng tôi đã đạt được mức độ thực tiễn cao với rất ít mã rất dễ lý do. Không có mã nào khác có thể nói chúng tôi chưa kiếm được mô tả này.

Điều đó làm cho nó là giải pháp "đúng" cho bạn? Đó là do bạn quyết định. Và không ai khác có thể làm điều đó cho bạn; chỉ có bạn biết nhu cầu của bạn là gì. Trong hầu hết các trường hợp, tôi đánh giá mã đơn giản, thực tế và linh hoạt hơn loại thông minh và nhanh chóng. Những gì bạn đánh giá có thể khác nhau, vì vậy hãy chọn những gì phù hợp với bạn.


Biên tập

Câu trả lời cũ của tôi tập trung hơn vào việc phân rã arrayEqualthành các thủ tục nhỏ. Đây là một bài tập thú vị, nhưng không thực sự là cách tốt nhất (thực tế nhất) để tiếp cận vấn đề này. Nếu bạn quan tâm, bạn có thể xem lịch sử sửa đổi này.


8
"loại mã tốt nhất thậm chí không cần bình luận" ... ghét phải nói nó, nhưng mã này có thể sử dụng nhiều bình luận hơn và / hoặc một tên khác - "so sánh" là khá mơ hồ. Nếu tôi đọc chính xác, "so sánh" của bạn về cơ bản là một "đệ quy" bị nguyền rủa. Tôi nghĩ. Hay là một "đệ quy" bị nguyền rủa? Hừm. Điều này đòi hỏi nhiều suy nghĩ hơn cần thiết. Có lẽ một cái tên tốt hơn sẽ là "mảngEquivalent", tận dụng thuật ngữ tiêu chuẩn của "mối quan hệ tương đương". Hoặc, thậm chí rõ ràng hơn (với tôi dù thế nào), "đệ quyEquivalent".
Don nở

1
@DonHatch cảm ơn vì cơ hội trả lời. "So sánh" ý bạn là arrayComparegì? Có chức năng được chế biến, nhưng nó khác với someevery. arrayComparecó một bộ so sánh và hai mảng để so sánh. Tôi đã chọn một tên chung cụ thể vì chúng ta có thể so sánh các mảng bằng cách sử dụng bất kỳ hàm tùy ý nào. Hàm được uốn cong để có thể được chuyên môn hóa để tạo các hàm so sánh mảng mới (ví dụ arrayEqual:). Bạn có thể đề nghị một cái tên tốt hơn? Những lĩnh vực nào bạn cảm thấy cần thêm ý kiến ​​hoặc giải thích? Tôi rất vui được thảo luận ^ _ ^
Cảm ơn bạn

1
Không chắc là quan điểm của tôi đã rõ chưa - nhưng quan điểm của tôi là, chức năng của bạn không thực sự có chức năng tùy ý , tôi không nghĩ - nó dự định có một mối quan hệ tương đương và nó trả về một mối quan hệ tương đương. Điều đó quan trọng-- nó sẽ không làm bất cứ điều gì hợp lý (tôi không nghĩ) nếu được cung cấp một số loại hàm nhị phân tùy ý khác như các hàm tôi đã đề cập, ngay cả những hàm mà mọi người thường gọi là "so sánh". Vì vậy, tôi nghĩ sẽ rất hữu ích khi đặt "tương đương" trong tên thay cho "so sánh".
Don nở

1
@ftor, tác giả: câu trả lời siêu hữu ích, công việc tốt, +1. Phản hồi: Bạn ủng hộ sự đơn giản, nhưng không có cách nào là một biểu thức có ba mũi tên trên một dòng đơn giản hoặc dễ hiểu cho nhiều nhà phát triển. Ví dụ: f => ([x, ... xs]) => ([y, ... ys]) =>. Tôi liên tục sử dụng nó và vẫn phải phân hủy tinh thần, thay vì "chỉ nhìn vào nó". Điểm thứ hai ftor là đúng, sử dụng mọi. Ngay cả khi cân nhắc lý do của bạn, về sự cân bằng, nó có vẻ tốt hơn không chỉ với tôi, mà còn từ quan điểm của bạn khi cố gắng suy luận triết lý thiết kế của bạn.
whitneyland

1
Tôi hiểu đây là một nơi để học hỏi, nhưng tôi đưa ra một giả định ở đây rằng lập trình viên trung bình nghiên cứu phong cách chức năng có thể biến đổi bất kỳ chức năng bị quấy rối nào thành một chức năng chưa được xử lý. Câu trả lời của tôi không đưa ra gợi ý rằng phong cách này có nghĩa là được sử dụng trong chương trình của riêng bạn - viết nó chưa được xử lý, viết nó bằng cách sử dụng quy tắc thụt lề của riêng bạn, viết nó theo cách bạn muốn - Tôi viết câu trả lời của mình theo phong cách mà tôi tin là thể hiện chương trình tốt nhất. Tôi cũng muốn mời những người khác thách thức cách chúng tôi thể hiện các chương trình của mình một cách tổng hợp
Cảm ơn bạn vào

54

Theo tinh thần của câu hỏi ban đầu:

Tôi muốn so sánh hai mảng ... lý tưởng, hiệu quả . Không có gì lạ mắt , chỉ đúng nếu chúng giống hệt nhau, và sai nếu không.

Tôi đã chạy thử nghiệm hiệu suất trên một số đề xuất đơn giản hơn được đề xuất ở đây với các kết quả sau (nhanh đến chậm):

trong khi (67%) bởi Tim Down

var i = a1.length;
while (i--) {
    if (a1[i] !== a2[i]) return false;
}
return true

mỗi (69%) bởi người dùng2782196

a1.every((v,i)=> v === a2[i]);

giảm (74%) bởi DEI

a1.reduce((a, b) => a && a2.includes(b), true);

tham gia & toString (78%) bởi Gaizka Allende & vivek

a1.join('') === a2.join('');

a1.toString() === a2.toString();

một nửa toString (90%) của Victor Palomo

a1 == a2.toString();

stringify (100%) bởi radtek

JSON.stringify(a1) === JSON.stringify(a2);

Lưu ý các ví dụ dưới đây giả định các mảng được sắp xếp, mảng một chiều. .lengthso sánh đã bị xóa đối với điểm chuẩn chung (thêm a1.length === a2.lengthvào bất kỳ đề xuất nào và bạn sẽ được tăng hiệu suất ~ 10%). Chọn bất kỳ giải pháp nào phù hợp nhất với bạn để biết tốc độ và giới hạn của từng giải pháp.

Lưu ý không liên quan: thật thú vị khi thấy mọi người nhận được tất cả John Waynes vui vẻ trên nút bỏ phiếu về câu trả lời hoàn toàn hợp pháp cho câu hỏi này.


Liên kết mở ra một bài kiểm tra trống.
Alexander Abakumov

Nếu bạn tăng kích thước mảng, những con số này không áp dụng (đặc biệt là cách tiếp cận giảm). Hãy thử với Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Narayon

nó chỉ hoạt động cho mảng nông
Ramesh Rajendran

28

Dựa trên câu trả lời của Tomáš Zato, tôi đồng ý rằng chỉ cần lặp qua các mảng là nhanh nhất. Ngoài ra (như những người khác đã nêu), hàm nên được gọi là bằng / bằng, không so sánh. Để giải quyết vấn đề này, tôi đã sửa đổi chức năng để xử lý việc so sánh các mảng cho sự tương đồng - tức là chúng có cùng các yếu tố, nhưng không theo thứ tự - để sử dụng cá nhân, và nghĩ rằng tôi sẽ ném nó vào đây cho mọi người xem.

Array.prototype.equals = function (array, strict) {
    if (!array)
        return false;

    if (arguments.length == 1)
        strict = true;

    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        if (this[i] instanceof Array && array[i] instanceof Array) {
            if (!this[i].equals(array[i], strict))
                return false;
        }
        else if (strict && this[i] != array[i]) {
            return false;
        }
        else if (!strict) {
            return this.sort().equals(array.sort(), true);
        }
    }
    return true;
}

Hàm này có một tham số bổ sung nghiêm ngặt mặc định là true. Tham số nghiêm ngặt này xác định nếu các mảng cần phải hoàn toàn bằng nhau về cả nội dung và thứ tự của các nội dung đó, hoặc chỉ đơn giản là chứa cùng một nội dung.

Thí dụ:

var arr1 = [1, 2, 3, 4];
var arr2 = [2, 1, 4, 3];  // Loosely equal to 1
var arr3 = [2, 2, 3, 4];  // Not equal to 1
var arr4 = [1, 2, 3, 4];  // Strictly equal to 1

arr1.equals(arr2);         // false
arr1.equals(arr2, false);  // true
arr1.equals(arr3);         // false
arr1.equals(arr3, false);  // false
arr1.equals(arr4);         // true
arr1.equals(arr4, false);  // true

Tôi cũng đã viết lên một jsfiddle nhanh chóng với chức năng và ví dụ này:
http://jsfiddle.net/Roundaround/DLkxX/


12

Mặc dù điều này có rất nhiều câu trả lời, nhưng câu trả lời mà tôi tin là có ích:

const newArray = [ ...new Set( [...arr1, ...arr2] ) ]

Nó không được nêu trong câu hỏi cấu trúc của mảng sẽ trông như thế nào, vì vậy Nếu bạn biết chắc chắn rằng bạn sẽ không có các mảng lồng nhau cũng như các đối tượng trong mảng của bạn (nó đã xảy ra với tôi, đó là lý do tại sao tôi đến với điều này Trả lời) đoạn mã trên sẽ hoạt động.

Điều gì xảy ra là chúng tôi sử dụng toán tử trải (...) để nối cả hai mảng, sau đó chúng tôi sử dụng Set để loại bỏ mọi trùng lặp. Một khi bạn có điều đó, bạn có thể so sánh kích thước của chúng, nếu cả ba mảng có cùng kích thước, bạn đều có thể đi.

Câu trả lời này cũng bỏ qua thứ tự các yếu tố , như tôi đã nói, tình huống chính xác đã xảy ra với tôi, vì vậy có lẽ ai đó trong tình huống tương tự có thể kết thúc ở đây (như tôi đã làm).


Chỉnh sửa1.

Trả lời câu hỏi của Dmitry Grinko: "Tại sao bạn sử dụng toán tử lây lan (...) tại đây - ... Bộ mới? Nó không hoạt động"

Xem xét mã này:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Bạn sẽ nhận được

[ Set { 'a', 'b', 'c' } ]

Để làm việc với giá trị đó, bạn cần sử dụng một số thuộc tính Set (xem https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/set ). Mặt khác, khi bạn sử dụng mã này:

const arr1 = [ 'a', 'b' ]
const arr2 = [ 'a', 'b', 'c' ]
const newArray = [ ...new Set( [...arr1, ...arr2] ) ]
console.log(newArray)

Bạn sẽ nhận được

[ 'a', 'b', 'c' ]

Đó là sự khác biệt, cái trước sẽ cho tôi một Bộ, nó cũng hoạt động vì tôi có thể lấy kích thước của Bộ đó, nhưng cái sau cho tôi mảng tôi cần, những gì trực tiếp hơn với độ phân giải.


Tại sao bạn sử dụng toán tử lây lan (...) tại đây - ... Bộ mới? Nó không hoạt động.
Dmitry Grinko

Dmitry Grinko Tôi tin rằng tôi đã trả lời câu hỏi của bạn trên Edit1. Nhưng tôi không chắc ý của bạn là gì khi nói 'nó không hoạt động', vì cả hai câu trả lời đều có thể cản trở bạn
Jeferson Euclides

10

Trên cùng một dòng với JSON.encode là sử dụng phép nối ().

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    //slice so we do not effect the original
    //sort makes sure they are in order
    //join makes it a string so we can do a string compare
    var cA = arrA.slice().sort().join(","); 
    var cB = arrB.slice().sort().join(",");

    return cA===cB;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];  //will return true

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //true

Vấn đề duy nhất là nếu bạn quan tâm đến các loại kiểm tra so sánh cuối cùng. Nếu bạn quan tâm về các loại, bạn sẽ phải lặp.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;

    //slice so we do not effect the orginal
    //sort makes sure they are in order
    var cA = arrA.slice().sort(); 
    var cB = arrB.slice().sort();

    for(var i=0;i<cA.length;i++){
         if(cA[i]!==cB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,b) );  //true
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

Nếu thứ tự nên giữ nguyên, vì nó chỉ là một vòng lặp, không cần sắp xếp.

function checkArrays( arrA, arrB ){

    //check if lengths are different
    if(arrA.length !== arrB.length) return false;


    for(var i=0;i<arrA.length;i++){
         if(arrA[i]!==arrB[i]) return false;
    }

    return true;

}

var a = [1,2,3,4,5];
var b = [5,4,3,2,1];
var c = [1,2,3,4];
var d = [1,2,3,4,6];
var e = ["1","2","3","4","5"];

console.log( checkArrays(a,a) );  //true
console.log( checkArrays(a,b) );  //false
console.log( checkArrays(a,c) );  //false
console.log( checkArrays(a,d) );  //false
console.log( checkArrays(a,e) );  //false

3
Điều này chỉ hoạt động đối với các mảng nhất định và sẽ rất chậm với các mảng lớn.
Tomáš Zato - Phục hồi Monica

2
Việc tạo JSON cũng đang lặp, bạn chỉ (hoặc có vẻ như vậy) không biết về nó. Bên cạnh việc lặp, việc tạo JSON cũng đòi hỏi nhiều bộ nhớ hơn - nó tạo ra 2 biểu diễn chuỗi của các mảng đã nói trước khi so sánh. Hàm downwote được triển khai để sắp xếp các câu trả lời từ tốt nhất đến xấu nhất. Tôi nghĩ rằng câu trả lời của bạn không phải là một câu trả lời hay, vì vậy tôi đã đánh giá thấp nó.
Tomáš Zato - Phục hồi Monica

2
Xin lỗi, tôi chỉ nói JSON thay vì .join(). Có thể nếu bạn tuyên bố giải pháp thứ hai của bạn là chính (vì đó là giải pháp tốt hơn, mặc dù không có vấn đề gì với các mảng đa chiều), tôi sẽ không đánh giá bạn theo cách đó. Cho đến nay, tôi đã bỏ qua tất cả các câu trả lời để chuyển đổi mảng thành chuỗi. Đồng thời, tôi đã nâng cấp tất cả những gì sử dụng đúng cách, trong trường hợp bạn cần điều đó để biết. Điều này có nghĩa là câu trả lời của @Tim Down và Bireys.
Tomáš Zato - Tái lập Monica

6
FAILS phiên bản đầu tiên: checkArrays([1,2,3] , ["1,2",3]) == truevà rất khó có thể đó là điều bạn muốn xảy ra!
Doin

2
@eprebello: Có, bạn có thể nhưng (ngoài hiệu quả của dải phân cách rất dài mà bạn đề xuất), điều đó có nghĩa là sẽ có các trường hợp cạnh (trong đó mảng xảy ra có chứa một chuỗi có dấu phân cách của bạn trong đó) . Điều này có thể không thành vấn đề nếu bạn biết điều gì đó về nội dung của các mảng (vì vậy bạn có thể chọn một dấu phân cách mà bạn chắc chắn sẽ không có trong các mục mảng), nhưng nếu bạn đang cố gắng viết một so sánh mảng chung chức năng, sau đó sử dụng join()như thế này làm cho nó lỗi tinh vi!
Doin

7

Đây là phiên bản Bản in:

//https://stackoverflow.com/a/16436975/2589276
export function arraysEqual<T>(a: Array<T>, b: Array<T>): boolean {
    if (a === b) return true
    if (a == null || b == null) return false
    if (a.length != b.length) return false

    for (var i = 0; i < a.length; ++i) {
        if (a[i] !== b[i]) return false
    }
    return true
}

//https://stackoverflow.com/a/16436975/2589276
export function arraysDeepEqual<T>(a: Array<T>, b: Array<T>): boolean {
    return JSON.stringify(a) === JSON.stringify(b)
}

Một số trường hợp thử nghiệm cho mocha:

it('arraysEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']

    expect(arraysEqual(a, b)).to.equal(true)
    expect(arraysEqual(c, d)).to.equal(true)
    expect(arraysEqual(a, d)).to.equal(false)
    expect(arraysEqual(e, f)).to.equal(true)
    expect(arraysEqual(f, g)).to.equal(false)
})

it('arraysDeepEqual', function () {
    let a = [1,2]
    let b = [1,2]
    let c = [2,3]
    let d = [2, 3]
    let e = ['car','apple','banana']
    let f = ['car','apple','banana']
    let g = ['car','apple','banan8']
    let h = [[1,2],'apple','banan8']
    let i = [[1,2],'apple','banan8']
    let j = [[1,3],'apple','banan8']

    expect(arraysDeepEqual(a, b)).to.equal(true)
    expect(arraysDeepEqual(c, d)).to.equal(true)
    expect(arraysDeepEqual(a, d)).to.equal(false)
    expect(arraysDeepEqual(e, f)).to.equal(true)
    expect(arraysDeepEqual(f, g)).to.equal(false)
    expect(arraysDeepEqual(h, i)).to.equal(true)
    expect(arraysDeepEqual(h, j)).to.equal(false)
})

6

Nếu bạn đang sử dụng khung kiểm tra như Mocha với thư viện xác nhận Chai , bạn có thể sử dụng đẳng thức sâu để so sánh các mảng.

expect(a1).to.deep.equal(a2)

Điều này sẽ trả về true chỉ khi các mảng có các phần tử bằng nhau tại các chỉ số tương ứng.


6

Nếu chúng chỉ là hai mảng số hoặc chuỗi, thì đây là một dòng một dòng nhanh

const array1 = [1, 2, 3];
const array2 = [1, 3, 4];
console.log(array1.join(',') === array2.join(',')) //false

const array3 = [1, 2, 3];
const array4 = [1, 2, 3];
console.log(array3.join(',') === array4.join(',')) //true

const mảng1 = [1]; const mảng2 = [1, 1]; console.log (mảng1.join ('') === mảng2.join ('')) // trả về true
Dan M.

không nên: mảng1.join ('') là '1' và mảng2.join ('') là '11'
Gaizka Allende

xin lỗi typo. Mảng đầu tiên phải là [11]. Khá rõ ràng là tại sao điều này xảy ra và làm thế nào để khắc phục.
Dan M.

Không chắc chắn về những gì bạn đang nói, nó khá đơn giản: [1] .join () là "1" và [1,1] .join () là "1,1", vì vậy chúng sẽ không bao giờ bằng nhau
Gaizka Allende

xin vui lòng, đọc bình luận của tôi một lần nữa cẩn thận hơn. Nếu bạn vẫn không thấy nó, vui lòng lấy một chiến lợi phẩm tại ideone.com/KFu427
Dan M.

5

Trong trường hợp của tôi, mảng so sánh chỉ chứa số và chuỗi. Hàm này sẽ hiển thị cho bạn nếu mảng chứa các phần tử giống nhau.

function are_arrs_match(arr1, arr2){
    return arr1.sort().toString() === arr2.sort().toString()
}

Hãy thử nghiệm nó!

arr1 = [1, 2, 3, 'nik']
arr2 = ['nik', 3, 1, 2]
arr3 = [1, 2, 5]

console.log (are_arrs_match(arr1, arr2)) //true
console.log (are_arrs_match(arr1, arr3)) //false

Câu hỏi không yêu cầu bạn sắp xếp, vì vậy giải pháp của bạn sai cho các ví dụ như are_arrs_equal([1,2], [2,1]). Ngoài ra, hãy xem các cuộc thảo luận khác trên trang này để biết lý do tại sao việc xâu chuỗi là không cần thiết, mong manh và sai.
đối xử tốt với các mod của bạn vào

are_arrs_equal([1,2], [2,1])trả lại truenhư mong đợi. Có lẽ giải pháp này không lý tưởng, nhưng nó hiệu quả với tôi.
yesnik 8/8/2016

Đó chính xác là vấn đề, hai cái đó không bằng nhau trong bất kỳ ý nghĩa lành mạnh nào của từ "bằng" cho một cấu trúc dữ liệu được sắp xếp . Chúng là các mảng, không phải là tập hợp và nếu bạn muốn đặt đẳng thức, bạn nên gọi nó là - và đang trả lời một câu hỏi khác. :-)
đối xử tốt với các mod của bạn vào

1
Tôi đồng ý với các ý kiến ​​trên, nhưng giải pháp này cũng hoạt động với tôi trong các mảng số nguyên đơn giản của tôi, trong đó thứ tự không quan trọng, vì vậy tôi sẽ sử dụng nó.
tomazahlin

1
Thất bại cho are_arrs_match([1,2], ["1,2"])(trả lại true). Và lưu ý rằng the sort()cuộc gọi sẽ sửa đổi các mảng đầu vào - điều này có thể không được mong muốn.
thử bắt cuối cùng vào

5

Điều này so sánh 2 mảng chưa được sắp xếp:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}

Mặc dù đắt tiền (về tài nguyên tính toán), đây là một giải pháp mạnh mẽ nên tốt cho nhiều loại khác nhau và không phụ thuộc vào việc sắp xếp!
dùng3,1415927


4

Chúng tôi có thể thực hiện việc này theo cách chức năng, bằng cách sử dụng every( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/every )

function compareArrays(array1, array2) {
    if (array1.length === array2.length)
        return array1.every((a, index) => a === array2[index])
    else
        return false
}

// test
var a1 = [1,2,3];
var a2 = [1,2,3];

var a3 = ['a', 'r', 'r', 'a', 'y', '1']
var a4 = ['a', 'r', 'r', 'a', 'y', '2']

console.log(compareArrays(a1,a2)) // true
console.log(compareArrays(a1,a3)) // false
console.log(compareArrays(a3,a4)) // false

4

Mã của bạn sẽ không xử lý trường hợp một cách thích hợp khi cả hai mảng có cùng các phần tử nhưng không theo cùng một thứ tự.

Hãy xem mã của tôi với ví dụ của bạn để so sánh hai mảng có các phần tử là số, bạn có thể sửa đổi hoặc mở rộng nó cho các loại phần tử khác (bằng cách sử dụng .join () thay vì .toString ()).

var a1 = [1,2,3];
var a2 = [1,2,3];
const arraysAreEqual = a1.sort().toString()==a2.sort().toString();
// true if both arrays have same elements else false
console.log(arraysAreEqual);


3

Giải pháp của Herer:

/**
 * Tests two data structures for equality
 * @param {object} x
 * @param {object} y
 * @returns {boolean}
 */
var equal = function(x, y) {
    if (typeof x !== typeof y) return false;
    if (x instanceof Array && y instanceof Array && x.length !== y.length) return false;
    if (typeof x === 'object') {
        for (var p in x) if (x.hasOwnProperty(p)) {
            if (typeof x[p] === 'function' && typeof y[p] === 'function') continue;
            if (x[p] instanceof Array && y[p] instanceof Array && x[p].length !== y[p].length) return false;
            if (typeof x[p] !== typeof y[p]) return false;
            if (typeof x[p] === 'object' && typeof y[p] === 'object') { if (!equal(x[p], y[p])) return false; } else
            if (x[p] !== y[p]) return false;
        }
    } else return x === y;
    return true;
};

Hoạt động với bất kỳ cấu trúc dữ liệu lồng nhau nào và rõ ràng bỏ qua các phương thức của đối tượng. Thậm chí đừng nghĩ đến việc mở rộng Object.prototype bằng phương thức này, khi tôi đã thử điều này một lần, jQuery đã bị hỏng;)

Đối với hầu hết các mảng, nó vẫn nhanh hơn hầu hết các giải pháp tuần tự hóa. Đây có lẽ là phương pháp so sánh nhanh nhất cho các mảng của các bản ghi đối tượng.


không tốt! những điều này là đúng: equal({}, {a:1})equal({}, null)lỗi này là:equal({a:2}, null)
kristianlm

3
JSON.stringify(collectionNames).includes(JSON.stringify(sourceNames)) ?  array.push(collection[i]) : null

Đây là cách tôi đã làm nó.


Giải pháp tốt - nhưng tôi tự hỏi trong một số tình huống nếu nó không luôn luôn hoạt động như dự định, chẳng hạn như với các nguyên thủy nhất định hoặc các mảng được lồng sâu? Tôi hy vọng nó hoạt động trong mọi hoàn cảnh
Ben Rondeau

3

So sánh 2 mảng:

var arr1 = [1,2,3];
var arr2 = [1,2,3];

function compare(arr1,arr2)
{
  if((arr1 == arr2) && (arr1.length == arr2.length))
    return true;
  else
    return false;
}

chức năng gọi

var isBool = compare(arr1.sort().join(),arr2.sort().join());

Câu trả lời này sẽ không hoạt động, vì === không hoạt động như mong đợi cho mảng.
Michael Yang

Câu trả lời hoạt động, mặc dù === không có bất kỳ ý nghĩa nào ở đây (vì sort () chỉ hoạt động trên mảng). Thậm chí == cũng sẽ hoạt động.
Amay Kulkarni

Hãy tự mình thử; Nó in sai nếu bạn chạy mã này. Điều này là do so sánh các giá trị tham chiếu của mảng theo cả == và === thay vì giá trị thực của chúng. == và === chỉ dành cho so sánh kiểu nguyên thủy.
Michael Yang

Nó trả về đúng, chúng tôi đã sử dụng nó, nhưng tôi đã xóa '===' vì nó không phải là cần thiết
Amay Kulkarni

Ah, tôi không nhận thấy bạn đang chuyển đổi thành một chuỗi và gọi hàm sau khi sắp xếp và tham gia; tôi xin lỗi
Michael Yang

3

Tôi tin vào đồng bằng JSvà với ECMAScript 2015, đó là ngọt ngào và đơn giản để hiểu.

var is_arrays_compare_similar = function (array1, array2) {

    let flag = true;

    if (array1.length == array2.length) {

        // check first array1 object is available in array2 index
        array1.every( array_obj => {
            if (flag) {
                if (!array2.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        // then vice versa check array2 object is available in array1 index
        array2.every( array_obj => {
            if (flag) {
                if (!array1.includes(array_obj)) {
                    flag = false;
                }
            }
        });

        return flag;
    } else {
        return false;
    }

}

hy vọng nó sẽ giúp được ai đó


1
Tại sao kiểm tra ngược lại cần thiết? Chúng ta biết các mảng có cùng kích thước, vì vậy nếu mọi mục trong mảng1 cũng được tìm thấy trong mảng2; Tại sao sau đó chúng ta phải kiểm tra xem mọi mục trong mảng2 cũng nằm trong mảng1?
JeffryHouser

2

Mở rộng ý tưởng Tomáš Zato. Array'spr.prototype.compare của Tomas phải được gọi là Array.prototype.compareIdentical.

Nó truyền lại:

[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 2]]) === false;
[1, "2,3"].compareIdentical ([1, 2, 3]) === false;
[1, 2, [3, 4]].compareIdentical ([1, 2, [3, 4]]) === true;
[1, 2, 1, 2].compareIdentical ([1, 2, 1, 2]) === true;

Nhưng thất bại về:

[[1, 2, [3, 2]],1, 2, [3, 2]].compareIdentical([1, 2, [3, 2],[1, 2, [3, 2]]])

Đây là phiên bản tốt hơn (theo ý kiến ​​của tôi):

Array.prototype.compare = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time
    if (this.length != array.length)
        return false;

    this.sort();
    array.sort();
    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(array[i]))
                return false;
        }
        else if (this[i] != array[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
}

http://jsfiddle.net/igos/bcfCY/


2
-1. Nếu nó 'thất bại' trên ví dụ bạn đã đưa ra, thì đó chỉ là trường hợp cho một định nghĩa hơi 'tùy tiện'. Tại sao bạn mong đợi hai mảng khác nhau được coi là bằng nhau? Bạn thậm chí chưa giải thích khái niệm 'bình đẳng' nào mà bạn đang cố gắng thực hiện ở đây, hoặc tại sao nó là một điều hợp lý hoặc hữu ích, nhưng có vẻ như bạn muốn các mảng đa chiều được so sánh như thể chúng bị sụp đổ xuống một chiều những cái. Nếu vậy, bạn thậm chí không đạt được điều đó: [1,2] .compare ([[1,2]]) sai với phiên bản của bạn, giống như với Tomáš.
Đánh dấu Amery

Dựa trên những gì tôi có thể suy ra, anh ta nói rằng [1, 2, 3, 4] và [1, 3, 2, 4] nên được so sánh như nhau (Thứ tự không thành vấn đề).
Gautham Badhrinathan

2
var a1 = [1,2,3,6];
var a2 = [1,2,3,5];

function check(a, b) {
  return (a.length != b.length) ? false : 
  a.every(function(row, index) {
    return a[index] == b[index];
  });
}  

check(a1, a2);

////// HOẶC LÀ ///////

var a1 = [1,2,3,6];
var a2 = [1,2,3,6];

function check(a, b) {
  return (a.length != b.length) ? false : 
  !(a.some(function(row, index) {
    return a[index] != b[index];
  }));
}  

check(a1, a2)

Bạn có thể cung cấp cho bạn một số chức năng mà sẽ không lặp lại hoàn toàn nếu chúng tôi nhận được điều kiện cần thiết thỏa mãn, như trên
Vasanth

2

Một cách tiếp cận khác với rất ít mã (sử dụng Array giảmArray bao gồm ):

arr1.length == arr2.length && arr1.reduce((a, b) => a && arr2.includes(b), true)

Nếu bạn muốn so sánh sự bình đẳng của trật tự:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • Các lengthĐảm bảo kiểm tra rằng tập các phần tử trong một mảng không chỉ là một tập hợp con của một trong những khác.

  • Bộ giảm tốc được sử dụng để đi qua một mảng và tìm kiếm từng mục trong mảng khác. Nếu một mục không được tìm thấy, hàm return trả về false.

    1. Trong ví dụ đầu tiên, nó đã được kiểm tra rằng một yếu tố được bao gồm
    2. Ví dụ thứ hai cũng kiểm tra thứ tự

1
bạn có thể giải thích một chút mã của bạn để làm cho câu trả lời này rõ ràng hơn không?
ted

1. so sánh độ dài của mảng để đảm bảo rằng một mảng không phải là tập hợp con của mảng kia
DEls

2. sử dụng bộ giảm tốc để đi qua một mảng và tìm kiếm từng mục trong mảng khác. Nếu một mục không được tìm thấy, hàm giảm sẽ trả về 'false'
DEls

@DEls: chỉnh sửa lời giải thích của bạn thành câu trả lời (hơi được điều chỉnh lại và mở rộng). Bây giờ bạn có thể xóa nhận xét của mình và gắn cờ nhận xét đầu tiên và bình luận này là lỗi thời.
thử bắt cuối cùng vào

2

Một cách tiếp cận đơn giản:

function equals(a, b) {
    if ((a && !b) || (!a && b) || (!a && !b) || (a.length !== b.length)) {
        return false;
    }

    var isDifferent = a.some(function (element, index) { 
        return element !== b[index];
    });

    return !isDifferent;
}

2

Đã có một số câu trả lời tuyệt vời. Nhưng tôi muốn chia sẻ ý tưởng bao phấn đã được chứng minh là đáng tin cậy trong việc so sánh các mảng. Chúng ta có thể so sánh hai mảng bằng JSON.opesify () . Nó sẽ tạo ra một chuỗi ra khỏi mảng và do đó so sánh hai chuỗi thu được từ hai mảng cho bằng nhau

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:1},2]) //true

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},2]) //false

JSON.stringify([1,{a:1},2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:1},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //false

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4],2]) //true

JSON.stringify([1,{a:2},[3,4],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[4]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //false

JSON.stringify([1,{a:2},[3,4,[5]],2]) == JSON.stringify([1,{a:2},[3,4,[5]],2]) //true

2

Đệ quy & hoạt động trên mảng NESTED :

function ArrEQ(a1,a2){
   return( 
        //:Are both elements arrays?
        Array.isArray(a1)&&Array.isArray(a2) 
        ?
        //:Yes: Test each entry for equality:
        a1.every((v,i)=>(ArrEQ(v,a2[i])))
        :
        //:No: Simple Comparison:
        (a1===a2)
   );;
};;

console.log( "Works With Nested Arrays:" );
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]],
    [1,2,3,[4,5,[6,"SAME/IDENTICAL"]]]
));;     
console.log( ArrEQ( 
    [1,2,3,[4,5,[6,"DIFFERENT:APPLES" ]]],
    [1,2,3,[4,5,[6,"DIFFERENT:ORANGES"]]]
));;  

2

Hoạt động với các đối số MULTIPLE với mảng NESTED :

//:Return true if all of the arrays equal.
//:Works with nested arrays.
function AllArrEQ(...arrays){
    for(var i = 0; i < (arrays.length-1); i++ ){
        var a1 = arrays[i+0];
        var a2 = arrays[i+1];
        var res =( 
            //:Are both elements arrays?
            Array.isArray(a1)&&Array.isArray(a2) 
            ?
            //:Yes: Compare Each Sub-Array:
            //:v==a1[i]
            a1.every((v,i)=>(AllArrEQ(v,a2[i])))
            :
            //:No: Simple Comparison:
            (a1===a2)
        );;
        if(!res){return false;}
    };;
    return( true );
};;

console.log( AllArrEQ( 
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
        [1,2,3,[4,5,[6,"ALL_EQUAL"   ]]],
));; 

2
In a simple way uning stringify but at same time thinking in complex arrays:

**Simple arrays**:  
var a = [1,2,3,4];  
var b = [4,2,1,4];  
JSON.stringify(a.sort()) === JSON.stringify(b.sort()) // true  

**Complex arrays**:  
var a = [{id:5,name:'as'},{id:2,name:'bes'}];  
var b = [{id:2,name:'bes'},{id:5,name:'as'}];  
JSON.stringify(a.sort(function(a,b) {return a.id - b.id})) === JSON.stringify(b.sort(function(a,b) {return a.id - b.id})) // true  

**Or we can create a sort function**  

function sortX(a,b) {  
return a.id -b.id; //change for the necessary rules  
}  
JSON.stringify(a.sort(sortX)) === JSON.stringify(b.sort(sortX)) // true  
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.