如何在JavaScript中比较数组?


988

我想比较两个数组...理想地,有效地比较。没有什么幻想,只要true它们是相同的,false如果不相同。毫不奇怪,比较运算符似乎不起作用。

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编码,但是有没有一种更快或更“更好”的方法来简单地比较数组而不必遍历每个值?


5
您可以先比较它们的长度,如果它们相等,则每个值。
TJHeuvel

55
是什么使两个数组对您相等?相同的元素?元素顺序相同?仅当可以将数组的元素序列化为JSON时,才可以将JSON编码。如果数组可以包含对象,那么您将深入多深?什么时候两个物体“相等”?
Felix Kling

48
@FelixKling,定义“平等”绝对是一个微妙的话题,但是对于从高级语言开始使用JavaScript的人们来说,没有诸如此类的愚蠢借口([] == []) == false
Alex D

4
@AlexD看起来数组使用引用相等,这是您期望的。如果您做不到,
那就

3
@AlexD我有点想不出一种不会发生这种情况的语言。在C ++中,您将比较两个指针-false。在Java中,您的操作与javascript中相同。在PHP中,幕后的东西会遍历整个数组-您将PHP称为高级语言吗?
托马什Zato -恢复莫妮卡

Answers:


877

要比较数组,请遍历它们并比较每个值:

比较数组:

// 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});

用法:

[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;

您可能会说“ 但是比较字符串要快得多-没有循环... ”,那么,您应该注意有ARE循环。第一个递归循环将Array转换为字符串,第二个递归循环比较两个字符串。因此,此方法比使用string更快

我认为,应将大量数据始终存储在数组中,而不是对象中。但是,如果使用对象,也可以部分比较它们。
就是这样:

比较对象:

上面我已经说过,即使此时两个对象实例包含相同的数据,它们也永远不会相等:

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

这是有原因的,因为在对象中可能存在例如私有变量。

但是,如果仅使用对象结构来包含数据,则仍然可以进行比较:

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;
}  

但是,请记住,这是用于比较JSON之类的数据,而不是类实例和其他内容。如果您想比较复杂的物体,请看这个答案,它是超长函数
要使用此Array.equals功能,您必须对原始功能进行一些编辑:

...
    // 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]) {
...

为这两个功能都做了一个小测试工具

奖励:使用indexOf和的嵌套数组contains

Samy Bencherif为您在嵌套数组中搜索特定对象的情况准备了有用的功能,可在以下位置找到:https : //jsfiddle.net/SamyBencherif/8352y6yw/


27
如果您想进行严格比较,请使用this[i] !== array[i]代替!=
Tim S.

38
应该调用您的方法,equals而不是compare。至少在.NET中,compare通常返回带符号的int,指示哪个对象大于另一个对象。请参阅:Comparer.Compare
奥利弗·

15
这样做不仅是正确的方法,而且效率更高。这是我为该问题中建议的所有方法准备的快速jsperf脚本。jsperf.com/comparing-arrays2
Tolga E

96
更改内置类型的原型绝对不是正确的方法
Jasper 2014年

31
此外,这不关乎是否易于重写,而是因为答案不应该推荐被认为是不好的做法(developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/…),并且应该绝对不可以在标题“正确的方式”下面进行此操作
Jasper 2014年

386

虽然这仅适用于标量数组(请参见下面的注释),但它很简短:

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

Rr,在带有箭头功能的ECMAScript 6 / CoffeeScript / TypeScript中:

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

(注意:“标量”在这里是指可以直接使用进行比较的值===。因此:数字,字符串,按引用的对象,按引用的函数。有关比较运算符的更多信息,请参见MDN参考。)

更新

从我的评论中可以看出,对数组进行排序和比较可能会得出准确的结果:

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

例如:

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

然后上面的代码将给 true


19
我喜欢这样,尽管读者应该意识到这仅适用于排序数组。
Ellen Spertus

13
它适用于任何种类的阵列,排序或不@espertus
米哈尔Miszczyszyn

36
对,就是这样。该函数应该比较两个数组,不管它们是否排序,它们的连续元素必须相等。
米哈尔Miszczyszyn

22
@espertus的确,如果元素在两个数组中的顺序不完全相同,则不会返回true。但是,相等性检查的目的不是检查它们是否包含相同的元素,而是检查它们是否具有相同顺序的相同元素。
昆汀·罗伊

7
如果您想检查两个数组都是平等的,含有相同的未分类的项目(但不包括多次使用),你可以使用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];不会按预期方式工作)
MEMS

208

无论您是要比较数组还是对象,我都喜欢在Underscore和Lodash中使用Underscore库进行数组/对象繁重的编码项目……

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

22
请注意,顺序很重要 _.isEqual([1,2,3], [2,1,3]) => false
Vitaliy Alekask

3
或者,如果您只需要isEqual功能,则可以始终使用lodash.isequal模块
hellatan

6
您可以使用_.difference(); 如果订单对您而言无关紧要
Ronan Quillevere

5
如果顺序无关紧要,我们可以在检查之前对数组进行排序_.isEqual([1,2,3].sort(), [2,1,3].sort()) => true
Filype

最简洁,直接的答案恕我直言:-)
Kieran Ryan

121

我认为这是使用JSON字符串化的最简单方法,在某些情况下它可能是最佳的解决方案:

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

这将对象转换a1a2使他们能够比较成字符串。在大多数情况下,顺序很重要,因为顺序可以使用上述答案之一所示的排序算法对对象进行排序。

请注意,您不再比较对象,而是对象的字符串表示形式。它可能不完全是您想要的。


好的答案,但是为什么[] == []返回false?两者都是简单的对象,为什么呢?
Pardeep Jain

4
@PardeepJain,这是因为默认情况下,当ECMAScript for Objects引用相同的内存位置时,其相等运算符将返回true。尝试var x = y = []; //现在相等返回true。
radtek

7
只是要注意,JSON字符串化功能并不快速。与更大的阵列一起使用肯定会导致延迟。
卢卡斯·里西斯

6
该问题专门询问是否有比使用JSON.stringify 更好/更快的方法。
唐·哈奇

它详细介绍了为什么在某些情况下这可能是一个好的解决方案。
radtek

61

不清楚“相同”是什么意思。例如,数组a及其b下面的数组是否相同(请注意嵌套数组)?

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

这是一个优化的数组比较函数,该函数使用严格相等性依次比较每个数组的对应元素,并且不对本身就是数组的数组元素进行递归比较,这意味着对于上面的示例,arraysIdentical(a, b)它将返回false。它在一般情况下有效,而join()基于JSON和基于解决方案的解决方案将无法:

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:从这个问题尚不清楚“相同”是什么意思。显然,这个答案只是做了一个浅浅的检查。我会加一个便条。
Tim Down

对于arraysIdentical([1、2,[3、2]],[1、2,[3、2]])失败;
Gopinath Shiva 2015年

4
@GopinathShiva:好吧,只有在您期望它返回时,它才会失败true。答案说明不会。如果需要比较嵌套数组,则可以轻松地添加递归检查。
蒂姆·唐

58

实用方式

我认为,如果某个实现只是“正确的”(“正确的”),而不是“错误的”解决方案,那么说一个特定的实现就是“正确的方式”是错误的。Tomáš的解决方案是对基于字符串的数组比较的明显改进,但这并不意味着它客观上是“正确的”。反正什么是的?是最快的吗?最灵活吗?这是最容易理解的吗?调试最快吗?它使用最少的操作吗?有副作用吗?没有任何一种解决方案可以拥有所有优点。

汤玛斯(Tomáš)可以说他的解决方案是快速的,但我也要说它不必要地复杂。它试图成为一种适用于所有数组(无论是否嵌套)的多合一解决方案。实际上,它不仅接受数组作为输入,而且仍然尝试给出“有效”答案。


泛型提供可重用性

我的回答将以不同的方式处理该问题。我将从通用arrayCompare过程开始,该过程仅涉及逐步遍历数组。从那里,我们将构建其他基本比较函数,例如arrayEqualarrayDeepEqual,等等

// 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)

我认为,最好的代码甚至不需要注释,这也不例外。这里发生的事情很少,您几乎无需费力就能了解此过程的行为。当然,您现在似乎对ES6语法有些陌生,但这只是因为ES6相对较新。

如类型所建议,arrayCompare采用比较函数f,以及两个输入数组xsys。在大多数情况下,我们要做的就是调用f (x) (y)输入数组中的每个元素。false如果用户定义的f返回值,我们会尽早返回false–感谢&&的短路评估。所以是的,这意味着比较器可以及早停止迭代,并在不必要时防止循环遍历输入数组的其余部分。


严格比较

接下来,使用我们的arrayCompare函数,我们可以轻松创建我们可能需要的其他函数。我们将从基础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

就那么简单。arrayEqual可以与被定义arrayCompare,并且进行比较的比较功能a,以b使用===(对于全等)。

请注意,我们还定义equal了它自己的功能。这突出显示了arrayCompare在其他数据类型(数组)的上下文中利用我们的一阶比较器的高阶函数的作用。


比较宽松

我们可以arrayLooseEqual使用a ==来轻松定义。现在,将1(数字)与'1'(字符串)进行比较时,结果将是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

深度比较(递归)

您可能已经注意到,这只是比较浅的比较。Tomáš的解决方案肯定是“ The Right Way™”,因为它确实进行了隐式深度比较,对吗?

好吧,我们的arrayCompare程序足够通用,可以轻松进行深度平等测试……

// 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

就那么简单。我们使用另一个高阶函数构建一个深度比较器。这次,我们arrayCompare使用一个自定义比较器包装,该比较器将检查aand b是数组。如果是这样,请arrayDeepCompare以其他方式重新应用ab与用户指定的比较器(f)进行比较。这使我们能够将深度比较行为与实际比较各个元素的方式分开。即,像上面的例子所示,我们可以深刻的比较使用equallooseEqual或其他任何比较,我们做。

因为arrayDeepCompare是咖喱,所以我们也可以像前面的示例一样部分应用它

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

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

对我来说,这已经是Tomáš解决方案的明显改进,因为我可以根据需要为数组明确选择浅表或深表比较。


对象比较(示例)

现在,如果您有一系列对象或东西呢?如果每个对象具有相同的id值,也许您想将这些数组视为“相等” ……

// 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

就那么简单。在这里,我使用了普通的JS对象,但是这种类型的比较器可以用于任何对象类型。甚至您的自定义对象。托马斯(Tomáš)的解决方案需要完全重新设计以支持这种平等测试

带有对象的深层阵列?没问题 我们构建了高度通用的通用功能,因此它们可以在各种用例中使用。

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

任意比较(示例)

或者,如果您想进行其他完全任意的比较呢?也许我想知道每一个x是否大于每个y……

// 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

少即是多

您可以看到我们实际上在用更少的代码做更多的事情。它arrayCompare本身并不复杂,我们制作的每个自定义比较器都有一个非常简单的实现。

轻松,我们可以定义正是我们希望的要比较两个数组-浅,深,严,活,一些对象属性,或一些任意的计算,或者它们的任意组合- 所有使用一个程序arrayCompare。甚至可以梦想一个RegExp比较器!我知道孩子们如何爱那些正则表达式……

是最快的吗?不。但这可能也不需要。如果速度是用来衡量代码质量的唯一指标,那么很多非常好的代码就会被扔掉-这就是为什么我将这种方法称为“实用方法”。或者更公平地说,一种实用方式。此说明适用于此答案,因为我并不是说此答案仅与其他答案相比是实际的;客观上是正确的。我们已经以很少的代码(很容易推理)获得了高度的实用性。没有其他代码可以说我们还没有获得此描述。

这是否使其成为您的“正确”解决方案?由决定。没有人能为您做到这一点;只有你知道你的需求是什么。在几乎所有情况下,我都认为简单,实用和通用的代码比聪明,快速的代码更有价值。您的价值可能会有所不同,因此请选择最适合您的。


编辑

我以前的答案更多地集中在分解arrayEqual为小程序上。这是一个有趣的练习,但实际上并不是解决此问题的最佳(最实用)方法。如果您有兴趣,可以查看此修订历史记录。


8
“最好的代码甚至不需要注释” ...讨厌这么说,但是此代码可能使用更多注释,和/或使用不同的名称-“比较”非常模糊。如果我没看错的话,您的“比较”本质上就是一个咖喱递归的“每个”。我认为。还是一个咖喱递归的“一些”?嗯 这需要比必要更多的思考。利用“等价关系”的标准术语,也许更好的名字是“ arraysEquivalent”。或者,更清晰(无论如何对我而言)是“递归等效”。
唐·哈奇

1
@DonHatch感谢您提供回复的机会。“比较”是什么意思arrayCompare?是的,该函数是可咖喱的,但不同于someeveryarrayCompare需要一个比较器和两个数组进行比较。我选择了一个特殊的通用名称,因为我们可以使用任意函数比较数组。该函数经过咖喱处理,因此可以专门创建新的数组比较函数(例如arrayEqual)。你能推荐一个更好的名字吗?您觉得哪些方面需要其他评论或解释?我很高兴讨论^ _ ^
谢谢你

1
不确定我的观点是否明确-但我的意思是,您的函数并不是真的打算采用任意函数,我认为不是-它打算采用 等价关系,并返回等价​​关系。这很重要-如果给定其他类型的任意二进制函数(如我提到的函数),甚至是人们通常称为“比较”的函数,它也不会做任何明智的操作(我不认为)。因此,我认为在名称中使用“等价”代替“比较”会有所帮助。
唐·哈奇

1
@ftor,作者:超级有用的答案,不错的工作,+ 1。反馈:您提倡简单,但对于许多开发人员而言,一条直线上带有三个箭头的表达方式简直还是容易理解。例如:f =>([x,... xs])=>([y,... ys])=>。我经常使用它,但仍然必须在精神上分解它,而不是“仅仅看它”。第二点是正确的,使用每一个。即使权衡您的原因,总的来说,这不仅对我来说更好,而且从您的角度来看,当您试图推断您的设计理念时,这似乎更好。
whitneyland '17

1
我知道这是一个学习的地方,但是我在这里假设普通的学习函数风格的程序员可以将任何咖喱函数转换为非咖喱函数。我的答案并没有暗示要在您自己的程序中使用此样式 –不写它,使用您自己的缩进规则编写它,按您的意愿编写它–我以我认为表达该风格的样式写我的答案最好的程序。我也想邀请其他人挑战我们句法表达程序的方式
谢谢

54

本着原始问题的精神:

我想比较两个数组...理想地,有效地比较。别无所求,如果它们相同,则为true,否则为false。

我一直在对此处提出的一些更简单的建议进行性能测试,结果如下(快到慢):

(67%)由Tim Down

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

(69%)由user2782196

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

通过DEI减少(74%)

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

Gaizka Allende和vivek的 jointoString(78%)

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

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

Victor Palomo的一半toString(90%)

a1 == a2.toString();

radtek的 stringify(100%)

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

请注意,下面的示例假定数组是排序的一维数组。.length删除了通用基准的比较(添加a1.length === a2.length到任何建议中,您将获得约10%的性能提升)。了解每种解决方案的速度和局限性,选择最适合您的解决方案。

无关紧要的注释:很有趣的是,人们在向下投票按钮上获得了所有令人兴奋的约翰·韦恩斯(John Waynes),获得了对该问题的完全合法答案。


该链接将打开一个空测试。
Alexander Abakumov

如果增加数组大小,则这些数字将不适用(尤其是reduce方法)。尝试Array.from({length: 1000}).map((a,v)=> $ {v}.padStart(10,2));
Narayon

它仅适用于浅层阵列
Ramesh Rajendran

28

基于TomášZato的答案,我同意仅迭代数组是最快的。另外(就像其他人已经说过的那样),该函数应称为等于/等于,而不是比较。有鉴于此,我修改了该函数以处理比较数组的相似性(即它们具有相同的元素,但顺序混乱)供个人使用,并认为我会将其放在这里供大家查看。

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;
}

此函数采用默认为true的strict附加参数。这个严格的参数定义数组在内容和内容顺序上是否需要完全相等,或者仅包含相同的内容。

例:

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

我还使用该函数和此示例编写了一个快速的jsfiddle:http :
//jsfiddle.net/Roundaround/DLkxX/


12

尽管有很多答案,但我认为这是有帮助的:

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

问题中没有说明数组的结构,因此,如果您确定您不会有嵌套的数组或数组中的对象(这是发生在我身上的原因,那么我就来了)答案)以上代码将起作用。

发生的情况是,我们使用散布运算符(...)合并两个数组,然后使用Set消除任何重复项。一旦有了它们,您就可以比较它们的大小,如果所有三个数组的大小都相同,那么您就可以开始使用了。

正如我所说的,这个答案也忽略了元素的顺序,就像我说的那样,确切的情况发生在我身上,所以也许处于相同情况的某人可能会在这里结束(就像我所做的那样)。


编辑1。

回答德米特里·格林科(Dmitry Grinko)的问题:“为什么在这里使用扩频运算符(...)-...新集?它不起作用”

考虑以下代码:

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

你会得到

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

为了使用该值,您需要使用一些Set属性(请参阅https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)。另一方面,当您使用此代码时:

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

你会得到

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

就是这样,前者会给我一个Set,因为我可以得到那个Set的大小,它也可以工作,但是后者会给我我需要的数组,这对分辨率更直接。


为什么在这里-... new Set使用扩展运算符(...)?没用
德米特里·格林科

Dmitry Grinko,我相信我在Edit1上回答了您的问题。但是我不确定您所说的“不起作用”是什么意思,因为这两个答案都可能使您陷入
困境

10

与JSON.encode相同,使用join()。

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

唯一的问题是,您是否关心最后一次比较测试的类型。如果您关心类型,则必须循环。

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

如果顺序应该保持不变,那么这仅仅是一个循环,则不需要排序。

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
这仅适用于某些阵列,对于大阵列将非常慢。
托马什Zato -恢复莫妮卡

2
生成JSON也在循环,您只是(或者看起来如此)不知道它。除了循环外,生成JSON还需要更多的内存-在比较之前,它会创建2个上述数组的字符串表示形式。Downwote功能的实现是按照从好到坏的顺序对答案进行排序。我认为您的回答不是一个很好的答案,因此我投票否决了。
托马什Zato -恢复莫妮卡

2
抱歉,我只是说JSON而不是.join()。也许如果您说第二个解决方案为主要解决方案(因为它是更好的解决方案,尽管对多维数组毫无用处),但我不会这样判断。到目前为止,我没有提及所有确实将数组转换为字符串的答案。同样,我建议所有使用正确方法的人,以防万一您需要知道这些。这意味着@Tim Down的答案和Bireys的答案。
托马什Zato -恢复莫妮卡

6
第一个版本失败: checkArrays([1,2,3] , ["1,2",3]) == true,这不太可能是您想要的!
Doin 2014年

2
@epascarello:是的,您可以但是(除了建议使用很长的分隔符的效率低下),这意味着在某些情况下(数组恰好包含分隔符在其中的字符串)checkArrays()函数的行为不正确。如果您对数组的内容有所了解,那么这可能不是问题(因此您可以选择一个分隔符,确保不会出现在数组项中),但是如果您要编写一般的数组比较函数,然后join()像这样使用,就使它微不足道!
Doin 2014年

7

这是打字稿版本:

//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)
}

摩卡咖啡的一些测试案例:

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

如果您正在使用带有Chai断言库的Mocha之类的测试框架,则可以使用深度相等来比较数组。

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

仅当数组在相应索引处具有相等的元素时,才应返回true。


6

如果它们仅是数字或字符串的两个数组,则这是一种快速的单行代码

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 array1 = [1]; const array2 = [1,1]; 的console.log(array1.join( '')=== array2.join( ''))//返回true
丹M.

它不应该:array1.join('')为“ 1”,而array2.join('')为“ 11”
Gaizka Allende,

对不起,错字。第一个数组应为[11]。为何发生这种情况以及如何解决这一点非常明显。
Dan M.

不确定您要做什么,这很简单:[1] .join()为“ 1”,[1,1] .join()为“ 1,1”,因此它们永远不会相等
Gaizka Allende

请再次仔细阅读我的评论。如果您仍然看不到它,请在ideone.com/KFu427
Dan M上

5

就我而言,比较数组仅包含数字和字符串。此函数将显示数组是否包含相同的元素。

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

让我们测试一下!

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

该问题不会要求您进行排序,因此对于诸如这样的示例,您的解决方案是错误的are_arrs_equal([1,2], [2,1])。另外,请参阅本页上的其他讨论以了解为什么不必要进行字符串化,易碎和错误。
好好对待您的mod

are_arrs_equal([1,2], [2,1])返回true预期。也许此解决方案并不理想,但对我有用。
yesnik '16

这正是问题所在,对于有序数据结构,这两个词在任何意义上都不相等,即“等于” 。它们是数组,而不是集合,如果要集合相等,则应称其为-并回答另一个问题。:-)
好好对待您的mod

1
我同意上面的评论,但是这种解决方案也适用于我的简单整数数组,其中顺序并不重要,因此我将使用它。
tomazahlin

1
失败are_arrs_match([1,2], ["1,2"])(返回true)。并请注意,the sort()调用将修改输入数组 -这可能不是理想的。
试试-最终

5

这将比较2个未排序的数组:

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

尽管很昂贵(就计算资源而言),但这是一个健壮的解决方案,应适用于各种类型,并且不依赖于排序!
user3.1415927

4

我们可以使用everyhttps://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

当两个数组具有相同的元素但顺序不同时,您的代码将无法正确处理这种情况。

请看一下我的代码示例,该示例比较了两个元素为数字的数组,您可以将其修改或扩展为其他元素类型(通过使用.join()而不是.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

这是我的解决方案:

/**
 * 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;
};

适用于任何嵌套数据结构,并且显然会忽略对象的方法。甚至不用考虑用这种方法扩展Object.prototype,当我尝试过一次时,jQuery坏了;)

对于大多数阵列,它仍然比大多数序列化解决方案要快。对于对象记录数组,这可能是最快的比较方法。


不好!这些给真:equal({}, {a:1})equal({}, null)这个错误了:equal({a:2}, null)
kristianlm

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

这就是我做到的。


好的解决方案-但我想知道在某些情况下它是否会始终无法按预期运行,例如某些基元或深度嵌套的数组?我希望它能在所有情况下都起作用
Ben Rondeau

3

比较2个数组:

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;
}

调用功能

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

该答案将不起作用,因为===的行为与数组预期的不同。
Michael Yang

答案是有效的,尽管===在这里没有任何意义(因为sort()仅适用于数组)。甚至==也可以。
Amay Kulkarni,

自己尝试一下;如果您运行此代码,它将显示为false。这是因为比较数组的参考值是通过==和===而不是它们的实际值。==和===仅用于原始类型比较。
Michael Yang

它返回true,我们已经使用过它,但是由于它不是必需的,我现在删除了“ ===”
Amay Kulkarni

啊,我没有注意到您正在转换为字符串并在排序和连接后调用该函数;对不起
Michael Yang

3

我相信,JS并带有ECMAScript 2015,这很容易理解。

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;
    }

}

希望对别人有帮助。


1
为什么需要反之亦然?我们知道数组的大小相同,因此,如果在array2中也找到了array1中的每个项目,我们为什么还要检查array2中的每个项目是否也在array1中?
JeffryHouser,

2

扩展TomášZato的想法。Tomas的Array.prototype.compare实际上应该称为Array.prototype.compareIdentical。

它继续:

[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;

但是失败:

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

这是更好的版本(在我看来):

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。如果它在您给出的示例中“失败”,则仅是“失败”的某种任意定义的情况。您为什么期望这两个不同的数组被视为相等?您甚至都没有解释您要在此处实现的“平等”的概念,或者为什么它是明智或有用的,但是您似乎想要比较多维数组,就好像它们被分解为一维数组一样那些。如果是这样,您甚至都没有实现:[1,2] .compare([[1,2]])与您的版本一样为false,就像Tomáš的版本一样。
Mark Amery 2013年

根据我的推论,他说[1、2、3、4]和[1、3、2、4]应该相等地比较(顺序无关紧要)。
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);

////// 要么 ///////

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)

您也可以执行一些功能,如果满足要求的条件,这些功能将不会完全迭代,例如上述
Vasanth

2

很少代码的另一种方法(使用Array reduceArray includes):

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

如果您还想比较顺序是否相等:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • length检查可确保一个数组中的元素集不只是另一个数组的子集。

  • reducer用于遍历一个数组并搜索另一数组中的每个项目。如果找不到一项,reduce函数将返回false

    1. 在第一个示例中,正在测试是否包含元素
    2. 第二个例子也检查订单

1
您能否解释一下您的代码以使答案更清晰?
TED

1.比较数组长度,以确保一个数组不是另一个数组的子集
DEls

2.使用reducer遍历一个数组并搜索另一数组中的每个项目。如果未找到任何一项,reduce函数将返回“ false”
DEls

@DEls:将您的解释编辑到答案中(略有改写和扩展)。您现在可以删除您的评论,并标记第一个评论和该评论为过时的评论。
试试,最终

2

一个简单的方法:

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

已经有一些不错的答案了。但是我想分享另一种想法,该想法在比较数组中被证明是可靠的。我们可以使用JSON.stringify()比较两个数组。它将在数组外创建一个字符串,从而比较从两个数组获得的两个字符串是否相等

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

递归&适用于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

NESTED数组一起使用MULTIPLE参数:

//: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  
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.