如何在JavaScript中比较数组?

发布于 2025-02-10 20:57:36 字数 337 浏览 3 评论 0 原文

我想比较两个阵列...理想情况下,有效。没什么好说的,只需 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确实可以简单地比较数组而无需遍历每个值,但是有没有更快或“更好”的方法?

I'd like to compare two arrays... ideally, efficiently. Nothing fancy, just true if they are identical, and false if not. Not surprisingly, the comparison operator doesn't seem to work.

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 encoding each array does, but is there a faster or "better" way to simply compare arrays without having to iterate through each value?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(30

离去的眼神 2025-02-17 20:57:36

要比较数组,请循环循环并比较每个值:

比较数组:

// 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;
    // if the argument is the same array, we can be sure the contents are same as well
    if(array === this)
        return true;
    // 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;

您可以说“ ,但是比较字符串要快得多 - 没有循环... ”,那么您应该在那里注明。是循环。将数组转换为字符串的第一个递归循环,然后比较两个字符串。因此,此方法比使用字符串快。

我相信,大量数据应始终存储在数组而不是对象中。但是,如果您使用对象,也可以部分比较它们。
是:

比较对象:

我上面说,两个对象实例也永远不会平等,即使它们目前包含相同的数据:

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

我制作了a 两个功能的小测试工具

奖励:带有 indexof 的嵌套数组

samy Bencherif已经准备了您正在搜索嵌套阵列中的特定对象的情况,在此处可用:https://jsfiddle.net/SamyBencherif/8352y6yw/

To compare arrays, loop through them and compare every value:

Comparing arrays:

// 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;
    // if the argument is the same array, we can be sure the contents are same as well
    if(array === this)
        return true;
    // 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});

Usage:

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

You may say "But it is much faster to compare strings - no loops..." well, then you should note there ARE loops. First recursive loop that converts Array to string and second, that compares two strings. So this method is faster than use of string.

I believe that larger amounts of data should be always stored in arrays, not in objects. However if you use objects, they can be partially compared too.
Here's how:

Comparing objects:

I've stated above, that two object instances will never be equal, even if they contain same data at the moment:

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

This has a reason, since there may be, for example private variables within objects.

However, if you just use object structure to contain data, comparing is still possible:

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

However, remember that this one is to serve in comparing JSON like data, not class instances and other stuff. If you want to compare more complicated objects, look at this answer and it's super long function.
To make this work with Array.equals you must edit the original function a little bit:

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

I made a little test tool for both of the functions.

Bonus: Nested arrays with indexOf and contains

Samy Bencherif has prepared useful functions for the case you're searching for a specific object in nested arrays, which are available here: https://jsfiddle.net/SamyBencherif/8352y6yw/

可可 2025-02-17 20:57:36

虽然这仅适用于标量阵列(浅层比较,请参见下面的注释),但它是简短的代码:

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

与上面相同,但在ecmascript 6 / coffeescript / tyscript中带有箭头函数:(

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

注意:'scalar'此处是指可以直接比较的值使用 === 。 JavaScript/Reference/operators/comparison_operators“ rel =“ noreferrer”> MDN参考有关比较操作员的更多信息)。

Update

根据我在评论中阅读的内容,对数组进行排序和比较可能会给出准确的结果:

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

例如:

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

那么上面的代码将返回 true

While this only works for scalar arrays (shallow comparison, see note below), it is short code:

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

Same as above but in ECMAScript 6 / CoffeeScript / TypeScript with Arrow Functions:

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

(Note: 'scalar' here means values that can be compared directly using === . So: numbers, strings, objects by reference, functions by reference. See the MDN reference for more info about the comparison operators).

UPDATE

From what I read in the comments, sorting the array and comparing may give accurate result:

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

Eg:

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

Then the above code would return true

囍笑 2025-02-17 20:57:36

我喜欢使用下划线库进行数组/对象重型编码项目...在下划线和lodash中,无论您是比较数组还是对象,它看起来都这样:

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

I like to use the Underscore library for array/object heavy coding projects ... in Underscore and Lodash whether you're comparing arrays or objects it just looks like this:

_.isEqual(array1, array2)   // returns a boolean
_.isEqual(object1, object2) // returns a boolean
温馨耳语 2025-02-17 20:57:36

我认为这是使用JSON Stringify进行操作的最简单方法,它可能是某些情况下最好的解决方案:

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

这将对象 a1 a2 转换为字符串可以比较。在大多数情况下,该顺序很重要,因为它可以使用上述答案之一中显示的排序算法对对象进行排序。

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

This I think is the simplest way to do it using JSON stringify, and it may be the best solution in some situations:

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

This converts the objects a1 and a2 into strings so they can be compared. The order is important in most cases, for that can sort the object using a sort algorithm shown in one of the above answers.

Please do note that you are no longer comparing the object but the string representation of the object. It may not be exactly what you want.

信仰 2025-02-17 20:57:36

本着原始问题的精神:

我想比较两个阵列...理想情况下,有效地什么都没有
花哨的
,如果它们是相同的,则是真的。

我一直在此处提出的一些更简单的建议进行绩效测试,其中包括以下结果 ):

while (67%) by tim down

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

every (69%) by User2782196

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

减少(74%)

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

join &amp; tostring (78%) by Gaizka alende&amp; vivek

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

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

fictor palomo

a1 == a2.toString();

stringify (100%) by radtek

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

注意以下示例假定阵列是分类的,单维数组。 .length 对公共基准的比较已被删除(添加 a1.length === a2.Length )。选择最适合您的解决方案知道每个解决方案的速度和限制。


第三方编辑

在我看来,JSbench现在从快速(100%)到较慢(例如11%)分类。代码示例包含 arrevery()和一个放缓的版本。


function arrEvery(a1,a2) 
{
    // user2782196: http://stackoverflow.com/a/19746771/308645
    return a1.every((v,i)=> v === a2[i]);
}

// slowed down
function arrEveryWithSlowDown(a1,a2) 
{
    setTimeout(() => {
        console.log("Slow down pal!");
    }, 1500);
    return a1.every((v,i)=> v === a2[i]);
}

Arrevery 的放缓版本的百分比较小。方括号中的数字可能是运行的环形 /操作数量。

In the spirit of the original question:

I'd like to compare two arrays... ideally, efficiently. Nothing
fancy
, just true if they are identical, and false if not.

I have been running performance tests on some of the more simple suggestions proposed here with the following results (fast to slow):

while (67%) by Tim Down

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

every (69%) by user2782196

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

reduce (74%) by DEIs

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

join & toString (78%) by Gaizka Allende & vivek

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

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

half toString (90%) by Victor Palomo

a1 == a2.toString();

stringify (100%) by radtek

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

Note the examples below assumes the arrays are sorted, single-dimensional arrays. .length comparison has been removed for a common benchmark (add a1.length === a2.length to any of the suggestions and you will get a ~10% performance boost). Choose whatever solutions that works best for you knowing the speed and limitation of each.

3rd party edit

It seems to me that jsbench is now sorting from fast (100%) to slower (for example 11%). The code sample contains arrEvery() and a slowed down version.


function arrEvery(a1,a2) 
{
    // user2782196: http://stackoverflow.com/a/19746771/308645
    return a1.every((v,i)=> v === a2[i]);
}

// slowed down
function arrEveryWithSlowDown(a1,a2) 
{
    setTimeout(() => {
        console.log("Slow down pal!");
    }, 1500);
    return a1.every((v,i)=> v === a2[i]);
}

The slowed down version of arrEvery has less percentage. The number in brackets might be the number of cycels / operations run.

jsbench.ch result array comparison

胡渣熟男 2025-02-17 20:57:36

我认为说特定实现的实用方法是“正确的方式™”,如果它仅是“正确”(“正确”),而“正确”的解决方案与“错误”解决方案相反 Tomáš的解决方案是对基于字符串的数组比较的明显改进,但这并不意味着它客观地“正确”。什么是正确?是最快的吗?它是最灵活的吗?是最简单的理解吗?调试是最快的吗?它使用最少的操作吗?它有任何副作用吗?没有一个解决方案可以拥有最好的一切。

托马斯(Tomáš)可以说他的解决方案很快,但我也想说这是不必要的复杂。它试图是一种适用于所有阵列的多合一解决方案。实际上,它甚至不仅接受数组作为输入,而且仍然试图给出一个“有效”的答案。


仿制药提供可重复性,

我的答案将以不同的方式解决问题。我将从一个通用 arraycompare 过程开始,该过程仅与踏上数组有关。从那里,我们将构建其他基本比较功能,例如 arrayequal arraydeepequal 等,

// 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 ,两个输入数组, xs ys 。在大多数情况下,我们要做的就是为输入数组中的每个元素调用 f(x)(y)。如果用户定义 f 返回 false> false - 感谢&amp;&amp;&amp; ',我们返回早期 false false 。短路评估。因此,是的,这意味着比较器可以尽早停止迭代,并在不需要的情况下阻止循环通过其余的输入阵列。


接下来,严格的比较

,使用我们的 arraycompare 函数,我们可以轻松创建可能需要的其他功能。我们将从基本 array equal 开始……

// 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 使用 ===的比较器函数进行定义。 (严格平等)。

请注意,我们还将等于定义为其自己的功能。这突出了 arraycompare 作为高阶功能的作用,可以在另一种数据类型(array)的上下文中使用我们的一阶比较器。


松散的比较,

我们可以使用 == 而不是很容易地定义 arrayloose equal 。现在,当比较 1 (编号)与'1'(string)时,结果将为 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áš的解决方案是“正确的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 ,该比较器将检查 a b 是数组。如果是这样,请重新申请 arrayDeepCompare 否则将 A b 与用户指定的比较器( f )进行比较。这使我们能够将深层比较行为与实际比较单个元素进行比较分开。即,如上所述,我们可以使用等于, loode> soce> 或我们进行的任何其他比较器进行深入比较。

因为 ArrayDeepCompare 是咖喱的,所以我们可以像以前的示例中一样部分地应用它

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

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

,这已经对Tomáš的解决方案有了明显的改进或根据需要对我的阵列进行深入比较。


对象比较(示例)

现在,如果您有一系列对象或其他东西怎么办? 也许您要将这些数组视为“相等”

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

如果每个对象都具有相同的 id 值…简单, 。在这里,我使用了香草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 比较器!我知道孩子们如何爱那些言论……

这是最快的吗?没有。但这可能也不需要。如果速度是用于衡量代码质量的唯一度量,那么许多非常出色的代码就会被抛弃 - 这就是为什么我将这种方法称为实用方法。也许要更公平, a 实用的方式。此描述适合此答案,因为我并不是说这个答案与其他答案相比仅是实际的。客观上是正确的。我们的实用性很高,几乎没有易于推理的代码。没有其他代码可以说我们没有赢得此描述。

这是否使您成为您的“正确”解决方案?这是您的决定。没有其他人可以为您做到这一点;只有你知道自己的需求。在几乎所有情况下,我都将直接,实用和多才多艺的代码重视而不是聪明和快速的代码。您的价值可能会有所不同,因此请选择对您有用的东西。


编辑

我的旧答案更专注于将 arrayequal 分解为微小的过程。这是一个有趣的练习,但实际上并不是解决此问题的最佳(最实用)方法。如果您有兴趣,可以看到此修订历史记录。

The Practical Way

I think it's wrong to say a particular implementation is "The Right Way™" if it's only "right" ("correct") in contrast to a "wrong" solution. Tomáš's solution is a clear improvement over string-based array comparison, but that doesn't mean it's objectively "right". What is right anyway? Is it the fastest? Is it the most flexible? Is it the easiest to comprehend? Is it the quickest to debug? Does it use the least operations? Does it have any side effects? No one solution can have the best of all the things.

Tomáš's could say his solution is fast but I would also say it is needlessly complicated. It tries to be an all-in-one solution that works for all arrays, nested or not. In fact, it even accepts more than just arrays as an input and still attempts to give a "valid" answer.


Generics offer reusability

My answer will approach the problem differently. I'll start with a generic arrayCompare procedure that is only concerned with stepping through the arrays. From there, we'll build our other basic comparison functions like arrayEqual and arrayDeepEqual, etc

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

In my opinion, the best kind of code doesn't even need comments, and this is no exception. There's so little happening here that you can understand the behaviour of this procedure with almost no effort at all. Sure, some of the ES6 syntax might seem foreign to you now, but that's only because ES6 is relatively new.

As the type suggests, arrayCompare takes comparison function, f, and two input arrays, xs and ys. For the most part, all we do is call f (x) (y) for each element in the input arrays. We return an early false if the user-defined f returns false – thanks to &&'s short-circuit evaluation. So yes, this means the comparator can stop iteration early and prevent looping through the rest of the input array when unnecessary.


Strict comparison

Next, using our arrayCompare function, we can easily create other functions we might need. We'll start with the elementary 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

Simple as that. arrayEqual can be defined with arrayCompare and a comparator function that compares a to b using === (for strict equality).

Notice that we also define equal as it's own function. This highlights the role of arrayCompare as a higher-order function to utilize our first order comparator in the context of another data type (Array).


Loose comparison

We could just as easily defined arrayLooseEqual using a == instead. Now when comparing 1 (Number) to '1' (String), the result will be 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

Deep comparison (recursive)

You've probably noticed that this is only shallow comparison tho. Surely Tomáš's solution is "The Right Way™" because it does implicit deep comparison, right ?

Well our arrayCompare procedure is versatile enough to use in a way that makes a deep equality test a breeze …

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

Simple as that. We build a deep comparator using another higher-order function. This time we're wrapping arrayCompare using a custom comparator that will check if a and b are arrays. If so, reapply arrayDeepCompare otherwise compare a and b to the user-specified comparator (f). This allows us to keep the deep comparison behavior separate from how we actually compare the individual elements. Ie, like the example above shows, we can deep compare using equal, looseEqual, or any other comparator we make.

Because arrayDeepCompare is curried, we can partially apply it like we did in the previous examples too

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

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

To me, this already a clear improvement over Tomáš's solution because I can explicitly choose a shallow or deep comparison for my arrays, as needed.


Object comparison (example)

Now what if you have an array of objects or something ? Maybe you want to consider those arrays as "equal" if each object has the same id value …

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

Simple as that. Here I've used vanilla JS objects, but this type of comparator could work for any object type; even your custom objects. Tomáš's solution would need to be completely reworked to support this kind of equality test

Deep array with objects? Not a problem. We built highly versatile, generic functions, so they'll work in a wide variety of use cases.

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

Arbitrary comparison (example)

Or what if you wanted to do some other kind of kind of completely arbitrary comparison ? Maybe I want to know if each x is greater than each 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

Less is More

You can see we're actually doing more with less code. There's nothing complicated about arrayCompare itself and each of the custom comparators we've made have a very simple implementation.

With ease, we can define exactly how we wish for two arrays to be compared — shallow, deep, strict, loose, some object property, or some arbitrary computation, or any combination of these — all using one procedure, arrayCompare. Maybe even dream up a RegExp comparator ! I know how kids love those regexps …

Is it the fastest? Nope. But it probably doesn't need to be either. If speed is the only metric used to measure the quality of our code, a lot of really great code would get thrown away — That's why I'm calling this approach The Practical Way. Or maybe to be more fair, A Practical Way. This description is suitable for this answer because I'm not saying this answer is only practical in comparison to some other answer; it is objectively true. We've attained a high degree of practicality with very little code that's very easy to reason about. No other code can say we haven't earned this description.

Does that make it the "right" solution for you ? That's up for you to decide. And no one else can do that for you; only you know what your needs are. In almost all cases, I value straightforward, practical, and versatile code over clever and fast kind. What you value might differ, so pick what works for you.


Edit

My old answer was more focused on decomposing arrayEqual into tiny procedures. It's an interesting exercise, but not really the best (most practical) way to approach this problem. If you're interested, you can see this revision history.

时间海 2025-02-17 20:57:36

目前尚不清楚您所说的“相同”。例如,阵列 a b 下方(请注意嵌套数组)吗?

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

这是一个优化的数组比较函数,它依次使用严格的平等比较每个数组的相应元素,并且不会对本身是数组的数组元素进行递归比较,这意味着对于上述示例, arraysidentical(a,b)将返回 false 。它在一般情况下起作用,基于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;
};

It's unclear what you mean by "identical". For example, are the arrays a and b below identical (note the nested arrays)?

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

Here's an optimized array comparison function that compares corresponding elements of each array in turn using strict equality and does not do recursive comparison of array elements that are themselves arrays, meaning that for the above example, arraysIdentical(a, b) would return false. It works in the general case, which JSON- and join()-based solutions will not:

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;
};
淡紫姑娘! 2025-02-17 20:57:36

在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的其他严格参数。该严格的参数定义了这些数组是否在内容和这些内容的顺序中都需要完全相等,或者只是仅包含相同的内容。

示例:

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,此示例:

Building off Tomáš Zato's answer, I agree that just iterating through the arrays is the fastest. Additionally (like others have already stated), the function should be called equals/equal, not compare. In light of this, I modified the function to handle comparing arrays for similarity - i.e. they have the same elements, but out of order - for personal use, and thought I'd throw it on here for everyone to see.

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

This function takes an additional parameter of strict that defaults to true. This strict parameter defines if the arrays need to be wholly equal in both contents and the order of those contents, or simply just contain the same contents.

Example:

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

I've also written up a quick jsfiddle with the function and this example:
http://jsfiddle.net/Roundaround/DLkxX/

妥活 2025-02-17 20:57:36

与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

On the same lines as JSON.encode is to use 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

Only problem is if you care about types which the last comparison tests.
If you care about types, you will have to loop.

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

If the order should remain the same, than it is just a loop, no sort is needed.

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
深海不蓝 2025-02-17 20:57:36

在我的情况下,比较数组仅包含数字和字符串。此功能将向您显示数组是否包含相同的元素。

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

In my case compared arrays contain only numbers and strings. This function will show you if arrays contain same elements.

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

Let's test it!

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
绝影如岚 2025-02-17 20:57:36

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

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

在阵列的结构看起来如何的问题中,这并没有说明,因此,如果您确定自己 won'' t在您的数组中有嵌套的数组和对象(这就是我发生的,这就是为什么我得出这个答案的原因)上述代码将起作用。

发生的事情是,我们使用传播操作员(...)进行con插,然后我们使用设置来消除任何重复项。一旦有了可以比较它们的尺寸,如果所有三个阵列的尺寸都与您相同的大小相同。

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


Edit1。

回答Dmitry Grinko的问题:“您为什么在此处使用传播操作员(...) - ...新集合?它不起作用”

考虑​​此代码:

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

您将获得

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

适用于您需要的值要使用一些设置的属性(请参阅)。
另一方面,当您使用此代码时:

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

您会明白

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

的是,前者会给我一套,因为我可以得到该集合的大小,但是后者给了我我需要的数组,更直接地解决了解决方案。

Even though this has a lot of answers, one that I believe to be of help:

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

It is not stated in the question how the structure of the array is going to look like, so If you know for sure that you won't have nested arrays nor objects in you array (it happened to me, that's why I came to this answer) the above code will work.

What happens is that we use spread operator ( ... ) to concat both arrays, then we use Set to eliminate any duplicates. Once you have that you can compare their sizes, if all three arrays have the same size you are good to go.

This answer also ignores the order of elements, as I said, the exact situation happened to me, so maybe someone in the same situation might end up here (as I did).


Edit1.

Answering Dmitry Grinko's question: "Why did you use spread operator ( ... ) here - ...new Set ? It doesn't work"

Consider this code:

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

You'll get

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

In order to work with that value you'd need to use some Set properties (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).
On the other hand, when you use this code:

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

You'll get

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

That's the difference, the former would give me a Set, it would work too as I could get the size of that Set, but the latter gives me the array I need, what's more direct to the resolution.

甜味超标? 2025-02-17 20:57:36

您可以简单地使用 iSequal 来自lodash库。这是非常有效和干净的。

import isEqual from "lodash/isEqual";

const isTwoArraysEqual = isEqual(array1, array2);

You can simply use isEqual from lodash library. It is very efficient and clean.

import isEqual from "lodash/isEqual";

const isTwoArraysEqual = isEqual(array1, array2);
耀眼的星火 2025-02-17 20:57:36

最短的

数字数量尝试:

a1==''+a2

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

console.log( a1==''+a2 )

注意:当数组还包含字符串,例如 a2 = [1,“ 2,3”] 时,此方法将不起作用。

Shortest

For an array of numbers try:

a1==''+a2

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

console.log( a1==''+a2 )

Note: this method will not work when the array also contains strings, e.g. a2 = [1, "2,3"].

感受沵的脚步 2025-02-17 20:57:36

这里有许多复杂的长答案,所以我只想贡献一个非常简单的答案:使用tostring()将数组变成一个简单的逗号分隔的字符串,您可以轻松地将其与===进行比较。

let a = [1, 2, 3]
let b = [1, 2, 3]
let c = [4, 2, 3]

console.log(a.toString())  // this outputs "1,2,3"
console.log(a.toString() === b.toString())  // this outputs true because "1,2,3" === "1,2,3"
console.log(a.toString() === c.toString())  // this outputs false because "1,2,3" != "4,2,3"

There are many complicated long answers in here, so I just want to contribute one very simple answer: use toString() to turn an array into a simple comma-separated string which you can easily compare with ===

let a = [1, 2, 3]
let b = [1, 2, 3]
let c = [4, 2, 3]

console.log(a.toString())  // this outputs "1,2,3"
console.log(a.toString() === b.toString())  // this outputs true because "1,2,3" === "1,2,3"
console.log(a.toString() === c.toString())  // this outputs false because "1,2,3" != "4,2,3"
静待花开 2025-02-17 20:57:36

这里有很多好的答案。这就是我通常这样做的方式 -

if ( arr1.length === arr2.length && arr1.every((a1) => arr2.includes(a1)) ) {
   // logic
}

每个()只有在所有元素通过给定的camparison
逻辑。如果在任何迭代中遇到一个错误,它将终止并
返回false。

时间复杂性将为o(n*m)。

Lot of good answers here. This is how I usually do it -

if ( arr1.length === arr2.length && arr1.every((a1) => arr2.includes(a1)) ) {
   // logic
}

every() will only return true if all elements pass the given camparison
logic. If it encounters a false, in any iteration, it terminates and
returns false.

Time complexity will be O(n*m).

吾性傲以野 2025-02-17 20:57:36

干得好,

const a = [1, 2, 3]
const b = [1, 2, 3, 4, 5]

const diff = b.filter(e => !a.includes(e))
console.log(diff)

上述大多数答案都不适用于无序列表。
这也适用于无序列表。

const a = [3, 2, 1]
const b = [1, 2, 3, 4, 5]

const diff = b.filter(e => !a.includes(e))
console.log(diff)

如果A的大小大于B

const a = [1, 2, 3, 4, 5]
const b = [3, 2, 1]

const diff = a.length > b.length ? a.filter(e => !b.includes(e)) : b.filter(e => !a.includes(e))
console.log(diff)

Here you go,

const a = [1, 2, 3]
const b = [1, 2, 3, 4, 5]

const diff = b.filter(e => !a.includes(e))
console.log(diff)

Most of the above answers dosen't work for unordered list.
This works for unordered lists too.

const a = [3, 2, 1]
const b = [1, 2, 3, 4, 5]

const diff = b.filter(e => !a.includes(e))
console.log(diff)

If size of a is greater than b,

const a = [1, 2, 3, 4, 5]
const b = [3, 2, 1]

const diff = a.length > b.length ? a.filter(e => !b.includes(e)) : b.filter(e => !a.includes(e))
console.log(diff)

要走就滚别墨迹 2025-02-17 20:57:36

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

可以查看我的代码与您的示例,其中比较了两个元素是数字的数组,您可以修改或扩展它适用于其他元素类型(通过使用.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);

Your code will not handle the case appropriately when both arrays have same elements but not in same order.

Have a look at my code with your example which compares two arrays whose elements are numbers, you might modify or extend it for other element types (by utilising .join() instead of .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);

旧瑾黎汐 2025-02-17 20:57:36

代码打高尔夫球

有很多答案,显示了如何有效地比较阵列。

以下是比较以代码字节来测量的两个int或(字符串)数组的最短最短

const a = [1, 2, 3]
const b = [1, 2, 3]

console.log("1. ", a.join() == b.join())
console.log("2. ", a.join() == [].join())

console.log("3. ", 1 + a == 1 + b)
console.log("4. ", 1 + [] == 1 + b)

// even shorter
console.log("4. b) ", a == "" + b)

// false positives (see flaws)
console.log("5. ", 1 + ["3"] == 1 + [3]) // type differences
console.log("6. ", 1 + ["1,2"] == 1 + ["1", "2"])

说明

这有效,因为当使用+运算符时,类型会自动转换以允许串联。在这种情况下,将 1 [1,2,3] 都转换为字符串。

在内部,JavaScript使用 [1,2,3] .join()将数组转换为字符串,然后添加它们,从而在 11,2,3 中添加。在两个数组上执行此操作时,可以简单地使用 === == 比较两个字符串。

使用此技术的缺陷

,比较不在乎要比较阵列中的元素是否具有不同的类型。 [1,2] 由于字符串转换而等于 [“ 1”,“ 2”]

编辑:正如评论中指出的那样,比较字符串数组可以产生误报,例如 [“ 1,2”] 是'等于' [“ 1”,“ 2”] 。如果您确定这些永远不会发生(例如,在许多代码打高尔夫球挑战中),这毫不犹豫。

免责声明

虽然这对于代码打高尔夫球很有用,但它可能不应在生产代码中使用。这两个缺陷指出也没有帮助。

Code Golfing

There are plenty of answers showing how to compare arrays efficiently.

Below is the shortest way to compare two int or (string) arrays, measured in bytes of code.

const a = [1, 2, 3]
const b = [1, 2, 3]

console.log("1. ", a.join() == b.join())
console.log("2. ", a.join() == [].join())

console.log("3. ", 1 + a == 1 + b)
console.log("4. ", 1 + [] == 1 + b)

// even shorter
console.log("4. b) ", a == "" + b)

// false positives (see flaws)
console.log("5. ", 1 + ["3"] == 1 + [3]) // type differences
console.log("6. ", 1 + ["1,2"] == 1 + ["1", "2"])

Explanation

This works because when using the + operator, the types are automatically converted to allow concatenation. In this case, the 1 and the [1, 2, 3] are both converted to a string.

Internally, JavaScript uses [1, 2, 3].join() to convert the array to a string and then adds them resulting in 11,2,3. When doing this on both arrays, one can simply use === or == to compare the two strings.

Flaws

Using this technique, the comparison does not care if the elements in the arrays to be compared are of different types. [1, 2] will be equal to ["1", "2"] because of the string conversion.

EDIT: As pointed out in the comments, comparing string arrays can produce false positives, such as ["1,2"] being 'equal' to ["1", "2"]. This is of no concern if you are sure these never occur (e.g. in many code golfing challenges).

Disclaimer

While this is useful for code golfing, it should probably not be used in production code. The two flaws pointed out aren't helping that either.

秋日私语 2025-02-17 20:57:36

这是一个打字稿版本:

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

Here is a Typescript version:

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

Some test cases for 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)
})
野稚 2025-02-17 20:57:36

有一个阶段1提案,在2020年推出通过将 array.prototype.equals 添加到语言中。这就是它的工作原理,没有任何库,monkeypatching或任何其他代码:

[1, 2, 3].equals([1, 2, 3]) // evaluates to true
[1, 2, undefined].equals([1, 2, 3]) // evaluates to false
[1, [2, [3, 4]]].equals([1, [2, [3, 4]]]) // evaluates to true

这只是到目前为止的暂定建议-TC39 现在将“投入时间来检查问题空间,解决方案和交叉切割问题”。如果它进入第2阶段,那么它很有可能最终被整合到该语言中。

There is a Stage 1 proposal, introduced in 2020, to allow for the easy comparison of arrays by adding Array.prototype.equals to the language. This is how it would work, without any libraries, monkeypatching, or any other code:

[1, 2, 3].equals([1, 2, 3]) // evaluates to true
[1, 2, undefined].equals([1, 2, 3]) // evaluates to false
[1, [2, [3, 4]]].equals([1, [2, [3, 4]]]) // evaluates to true

It's only a tentative proposal so far - TC39 will now "devote time to examining the problem space, solutions and cross-cutting concerns". If it makes it to stage 2, it has a good chance of eventually being integrated into the language proper.

苦妄 2025-02-17 20:57:36

如果您使用的是测试框架,例如 mocha 使用 chai 断言库,您可以使用 deep 数组。

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

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

If you are using a testing framework like Mocha with the Chai assertion library, you can use deep equality to compare arrays.

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

This should return true only if the arrays have equal elements at corresponding indices.

幼儿园老大 2025-02-17 20:57:36

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

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

If they are two arrays of numbers or strings only, this is a quick one-line one

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
落在眉间の轻吻 2025-02-17 20:57:36

另一种代码很少的方法(使用 /a> and “ noreferrer”

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)
  • 长度检查确保一个数组中的元素集不仅是另一个数组的子集。

  • 还原器用于漫步在一个数组中,并在另一个数组中搜索每个项目。如果找不到一个项目,则降低功能返回 false

    1. 在第一个示例中,正在测试其中包括一个元素
    2. 第二个示例检查订单

Another approach with very few code (using Array reduce and Array includes):

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

If you want to compare also the equality of order:

arr1.length == arr2.length && arr1.reduce((a, b, i) => a && arr2[i], true)
  • The length check ensures that the set of elements in one array isn't just a subset of the other one.

  • The reducer is used to walk through one array and search for each item in other array. If one item isn't found the reduce function returns false.

    1. In the first example it's being tested that an element is included
    2. The second example check for the order too
橘寄 2025-02-17 20:57:36

我们可以使用每个 https://developer.mozilla.org/en/docs/web/javascript/reference/global_objects/array/every/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

We could do this the functional way, using 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
苏别ゝ 2025-02-17 20:57:36

这比较了2个未分类的阵列:

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

This compares 2 unsorted arrays:

function areEqual(a, b) {
  if ( a.length != b.length) {
    return false;
  }
  return a.filter(function(i) {
    return !b.includes(i);
  }).length === 0;  
}
本宫微胖 2025-02-17 20:57:36

一种简单的方法:

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

A simple approach:

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;
}
通知家属抬走 2025-02-17 20:57:36

已经有一些很棒的答案。但是我想分享Anther的想法,事实证明,它在比较数组时是可靠的。我们可以使用 .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

Already some great answers.But i would like to share anther idea which has proven to be reliable in comparing arrays. We can compare two array using JSON.stringify ( ) . It will create a string out the the array and thus compare two obtained strings from two array for equality

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
圈圈圆圆圈圈 2025-02-17 20:57:36
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  
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  
铁轨上的流浪者 2025-02-17 20:57:36

这里有可能进行未分类阵列和自定义比较的可能性:

    const array1 = [1,3,2,4,5];
    const array2 = [1,3,2,4,5];
    
    const isInArray1 = array1.every(item => array2.find(item2 => item===item2))
    const isInArray2 = array2.every(item => array1.find(item2 => item===item2))
    
    const isSameArray = array1.length === array2.length && isInArray1 && isInArray2
    
    console.log(isSameArray); //true

Here a possibility for unsorted arrays and custom comparison:

    const array1 = [1,3,2,4,5];
    const array2 = [1,3,2,4,5];
    
    const isInArray1 = array1.every(item => array2.find(item2 => item===item2))
    const isInArray2 = array2.every(item => array1.find(item2 => item===item2))
    
    const isSameArray = array1.length === array2.length && isInArray1 && isInArray2
    
    console.log(isSameArray); //true
清风疏影 2025-02-17 20:57:36

简单的

type Values = number | string;

/** Not sorted array */
function compare<Values>(a1: Array<Values>, a2: Array<Values>): boolean {
    if (a1.length !== a2.length) {
        return false;
    }

    /** Unique values */
    const set1 = new Set<Values>(a1);
    const set2 = new Set<Values>(a2);
    if (set1.size !== set2.size) {
        return false;
    }

    return [...set1].every((value) => [...set2].includes(value));
}

compare([1, 2, 3], [1, 2, 3]);    // true
compare([1, 2, 3], [1, 3, 2]);    // true
compare([1, 1, 1], [1, 2, 3]);    // false
compare([1, 1, 2, 3], [1, 2, 3]); // false

/** Sorted arrays, faster method */
function compareSorted<Values>(a1: Array<Values>, a2: Array<Values>): boolean {
    if (a1.length !== a2.length) {
        return false;
    }

    /** Unique values */
    const set1 = new Set<Values>(a1);
    const set2 = new Set<Values>(a2);
    if (set1.size !== set2.size) {
        return false;
    }

    return [...set1].every((value, index) => value === [...set2][index]);
}

compareSorted([1, 2, 3], [1, 2, 3]);    // true
compareSorted([1, 2, 3], [1, 3, 2]);    // false
compareSorted([1, 1, 1], [1, 2, 3]);    // false
compareSorted([1, 1, 2, 3], [1, 2, 3]); // false

Simple

type Values = number | string;

/** Not sorted array */
function compare<Values>(a1: Array<Values>, a2: Array<Values>): boolean {
    if (a1.length !== a2.length) {
        return false;
    }

    /** Unique values */
    const set1 = new Set<Values>(a1);
    const set2 = new Set<Values>(a2);
    if (set1.size !== set2.size) {
        return false;
    }

    return [...set1].every((value) => [...set2].includes(value));
}

compare([1, 2, 3], [1, 2, 3]);    // true
compare([1, 2, 3], [1, 3, 2]);    // true
compare([1, 1, 1], [1, 2, 3]);    // false
compare([1, 1, 2, 3], [1, 2, 3]); // false

/** Sorted arrays, faster method */
function compareSorted<Values>(a1: Array<Values>, a2: Array<Values>): boolean {
    if (a1.length !== a2.length) {
        return false;
    }

    /** Unique values */
    const set1 = new Set<Values>(a1);
    const set2 = new Set<Values>(a2);
    if (set1.size !== set2.size) {
        return false;
    }

    return [...set1].every((value, index) => value === [...set2][index]);
}

compareSorted([1, 2, 3], [1, 2, 3]);    // true
compareSorted([1, 2, 3], [1, 3, 2]);    // false
compareSorted([1, 1, 1], [1, 2, 3]);    // false
compareSorted([1, 1, 2, 3], [1, 2, 3]); // false
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文