如何知道两个数组是否具有相同的值


104

我有两个数组:一个数组填充了来自ajax请求的信息,另一个数组存储了用户单击的按钮。我使用以下代码(我填写了示例编号):

var array1 = [2, 4];
var array2 = [4, 2]; //It cames from the user button clicks, so it might be disordered.
array1.sort(); //Sorts both Ajax and user info.
array2.sort();
if (array1==array2) {
    doSomething();
}else{
    doAnotherThing();
}

但是false,即使两个数组相同,但名称不同,它总是给出。(我在Chrome的JS控制台中对此进行了检查)。那么,有什么办法可以知道这两个数组是否包含相同的内容?为什么给false?我如何知道第一个数组中的哪个值不在第二个数组中?


1
我很确定您需要遍历数组的每个元素。
托马斯·李

您知道为什么它返回false吗?好奇。
RobW 2014年


Answers:


36
function arraysEqual(_arr1, _arr2) {

    if (!Array.isArray(_arr1) || ! Array.isArray(_arr2) || _arr1.length !== _arr2.length)
      return false;

    var arr1 = _arr1.concat().sort();
    var arr2 = _arr2.concat().sort();

    for (var i = 0; i < arr1.length; i++) {

        if (arr1[i] !== arr2[i])
            return false;

    }

    return true;

}

请注意,这不会像以前的答案那样修改原始数组。


2
排序需要nlog(n)时间。您不需要排序。这个答案stackoverflow.com/a/55614659/3209523以线性时间工作。
canbax

使用打字稿,Array.isArray()导致错误,将其删除正常。
Ariel Frischer

88

如果您的数组项不是对象(例如,如果它们是数字或字符串),则可以比较它们的联接字符串,以查看它们是否具有相同的成员顺序(例如,

var array1= [10, 6, 19, 16, 14, 15, 2, 9, 5, 3, 4, 13, 8, 7, 1, 12, 18, 11, 20, 17];
var array2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];

if(array1.sort().join(',')=== array2.sort().join(',')){
    alert('same members');
}
else alert('not a match');

2
这将对具有唯一标识toString值的原语或对象有效,但不适用于任何对象。
devios1 2012年

谢谢!简洁的解决方案
Gaston Sanchez

3
提防空项和排序。我最终以字符串进行比较,例如“,2,2,3”和“ 2,2,3”,这当然不是严格相等的。
barbara.post,2015年

2
可能无法输入字符串,例如['a', 'b']['a,b']。我只推荐这种技术用于小的一次性脚本。
Alex

1
@alex-在我的情况下,字符串中允许使用逗号,但不允许使用半冒号,因此我使用了';' 加入而不是逗号
a2345sooted '18

45

如果只想检查两个数组是否具有相同的值(不管出现的次数和每个值的顺序),则可以使用lodash进行操作

_.isEmpty(_.xor(array1, array2))

简短,简单,漂亮!


1
我似乎xor在下划线文档中找不到?您是否正在考虑IODash?
Patrick Mencias-lewis 2015年

44
Array.prototype.compare = function(testArr) {
    if (this.length != testArr.length) return false;
    for (var i = 0; i < testArr.length; i++) {
        if (this[i].compare) { //To test values in nested arrays
            if (!this[i].compare(testArr[i])) return false;
        }
        else if (this[i] !== testArr[i]) return false;
    }
    return true;
}

var array1 = [2, 4];
var array2 = [4, 2];
if(array1.sort().compare(array2.sort())) {
    doSomething();
} else {
    doAnotherThing();
}

也许?


谢谢!它可以按需工作。我修改了一些功能,所以我也可以知道有多少不匹配。
卡洛斯·普雷西奥索2011年

对于[2,4] [4,2]为false。
Suraz Khanal

@SurazKhanal仍然需要排序
Aaron

26

为什么您的代码不起作用

JavaScript具有原始数据类型和非原始数据类型。

对于原始数据类型,=====检查是否在酒吧两边的东西具有相同的值。这就是为什么1 === 1

对于非原始数据类型如数组,=====检查是否引用相等。也就是说,他们检查是否arr1arr2是否为同一对象。在您的示例中,两个数组以相同的顺序具有相同的对象,但不相等。

解决方案

当且仅当以下情况,两个数组arr1和才arr2具有相同的成员:

  • 一切都arr2arr1

  • 一切都arr1arr2

因此,这可以解决问题(ES2016):

const containsAll = (arr1, arr2) => 
                arr2.every(arr2Item => arr1.includes(arr2Item))

const sameMembers = (arr1, arr2) => 
                        containsAll(arr1, arr2) && containsAll(arr2, arr1);

sameMembers(arr1, arr2); // `true`

使用Underscore的第二种解决方案更接近于您尝试做的事情:

arr1.sort();
arr2.sort();

_.isEqual(arr1, arr2); // `true`

它之所以有效,是因为isEqual检查了“深度相等性”,这意味着它不仅查看引用相等性而且比较值。

第三个问题的解决方案

您还询问了如何找出其中arr1未包含的内容arr2

可以做到这一点(ES2015):

const arr1 = [1, 2, 3, 4];
const arr2 = [3, 2, 1];

arr1.filter(arr1Item => !arr2.includes(arr1Item)); // `[4]`

您还可以使用Underscore的difference:方法:

_.difference(arr1, arr2); // `[4]`

更新

请参阅@Redu的评论—我的解决方案是针对的sameMembers,但您可能想到的sameMembersInOrder也称为- deepEquals

更新2

如果您不关心数组成员的顺序,则ES2015 +的Set数据结构可能比更好Array。有关如何实现isSupersetdifference使用危险的猴子修补程序,请参见MDN注释


1
您的解决方案是错误的。“两个数组arr1和arr2在以下情况下具有相同的成员:且仅当:arr2中的所有内容都在arr1中,而arr1中的所有内容都在arr2中”,这也是错误的。这是一个数组而不是集合。因此sameMembers([1,1,2],[2,1,2]);应返回false。
Redu

1
@Redu猜测这取决于“相同成员”的含义-我认为它的意思是“具有相同成员”。我认为sameMembers([1,1,2],[2,1,2])应该返回truesameMembersInOrder([1,1,2],[2,1,2])AKA deepEquals([1,1,2],[2,1,2])应该回来false
Max Heiber

您的第三个解决方案arr1.filter...仅适用于检查arr2是否具有arr1的所有元素,而不是相反。
Aakash Verma


9

我们的目标基本上是检查2个数组是否相等。set是数学定义的set。渐近最快的排序需要O(nlog(n))时间。因此,如果对数组进行排序,则至少需要O(nlog(n))时间。但是您可以更快地完成此任务,这对于字典数据结构而言渐近需要O(n)时间(平均情况而不是最坏情况)。在JS中,字典只是具有键和值的对象。

/** assumes array elements are primitive types
* check whether 2 arrays are equal sets.
* @param  {} a1 is an array
* @param  {} a2 is an array
*/
function areArraysEqualSets(a1, a2) {
  const superSet = {};
  for (const i of a1) {
    const e = i + typeof i;
    superSet[e] = 1;
  }

  for (const i of a2) {
    const e = i + typeof i;
    if (!superSet[e]) {
      return false;
    }
    superSet[e] = 2;
  }

  for (let e in superSet) {
    if (superSet[e] === 1) {
      return false;
    }
  }

  return true;
}

请注意,此函数适用于基本类型的数组,并假定a1a2为数组。


5

那这个呢?我认为ES 2017:

const array1 = [1, 3, 5];
const array2 = [1, 5, 3];

const isEqual = (array1.length === array2.length) && (array1.every(val => array2.includes(val)));
console.log(isEqual);

第一个条件检查两个数组的长度是否相同,第二个条件检查第一个数组是否为第二个数组的子集。然后,将这两个条件组合在一起,就可以比较两个数组的所有项目,而不必考虑元素的顺序。

上面的代码仅在两个数组都有非重复项的情况下才有效。


3

比较这两个数组时,将比较表示数组的对象,而不是内容。

您必须使用一个函数来比较两者。您可以编写自己的代码,简单地循环一个,然后在检查长度相同后将其与另一个进行比较。


3

使用ES6进行浅层相等的简单解决方案:

const arr1test = arr1.slice().sort()
const arr2test = arr2.slice().sort()
const equal = !arr1test.some((val, idx) => val !== arr2test[idx])

创建每个数组的浅表副本并对其进行排序。然后用于some()遍历arr1test值,将每个值与arr2test具有相同索引的值进行比较。如果所有值都相等,则some()返回false,然后equal求值为true

也可以使用every(),但必须循环遍历数组中的每个元素才能满足true结果,而some()一旦发现不相等的值,它将立即保释:

const equal = arr1test.every((val, idx) => val === arr2test[idx])

2

我在Game项目中有简单的整数值,
每个数组中的值数量较少,而且还需要原始数组保持不变,
所以我做了以下工作,效果很好。(已编辑代码以粘贴到此处)

var sourceArray = [1, 2, 3];
var targetArray = [3, 2, 1];

if (sourceArray.length !== targetArray.length) {
    // not equal
    // did something
    return false;
}

var newSortedSourceArray = sourceArray.slice().sort();
var newSortedTargetArray = targetArray.slice().sort();

if (newSortedSourceArray.toString() !== newSortedTargetArray.toString()) { // MAIN CHECK
    // not equal
    // did something
    return false;
}
else {
    // equal
    // did something
    // continued further below
}

// did some more work

return true;

希望能有所帮助。


2

使用ES6

我们将使用Ramda的equals函数,但可以使用Lodash或Underscore的函数isEqual

const R = require('ramda');

const arraysHaveSameValues = (arr1, arr2) => R.equals( [...arr1].sort(), [...arr2].sort() )

使用散布运算符,我们避免了对原始数组的变异,并且使函数保持纯净。


2

您可以使用reduce而不是循环来显得聪明,但是冒着让其他开发人员将您视为智能资产的风险。

function isArrayContentSame(a, b) {
  if (Array.isArray(a) && Array.isArray(b) && a.length == b.length) {
    a = a.concat().sort()
    b = b.concat().sort()
    return a.reduce((acc,e,i) => acc && e === b[i], true)
  } else {
    return false;
  }
}

1

如果数组中的项目是基元(数字或单个字符),则可以使用比较长度和使用集合的组合。

function equalArrayItems(arr1, arr2) {
  if (arr1.length !== arr2.length) return false
  const set1 = new Set(arr1)
  const set2 = new Set(arr2)
  const set3 = new Set(arr1, arr2)
  return set1.size === set3.size && set2.size === set3.size
}

1

已经是2020年了,但是我注意到大多数其他解决方案都使用sort O(n * log n),使用库或具有O(n ^ 2)的复杂性。

这是一个线性复杂度为O(n)的纯Javascript解决方案:

/**
 * Check if two arrays of strings or numbers have the same values regardless of the order
 * @param {string[]|number[]} arr1
 * @param {string[]|number[]} arr2
 * @return {boolean}
 */    
compareArrays = (arr1, arr2) => {
    if (arr1.length !== arr2.length) return false;
    const lk1 = {};
    const lk2 = {};
    let i = arr1.length;
    while (--i >= 0) {
        lk1[arr1[i]] = true;
        lk2[arr2[i]] = true
    }
    i = arr1.length;
    while (--i >= 0) {
        const v = arr1[i];
        if (lk1[v] !== lk2[v]) return false;
    }
    return true
}

测试:

compareArrays([2, 4], [4, 2]) => true
compareArrays([2, 4], [4, 2, 7]) => false
compareArrays([], []) => true

1
嘿,这是一个很棒的条目!这很令人费解,但确实有道理。我有一个问题:我对Big O表示法不是很熟悉,但是肯定是O(2n)这个算法吗?不过不要以为这有很大的区别。
卡洛斯·普雷西奥索

1
@CarlosPrecioso是正确的,并且O(2n)= O(n)。复杂度不会因乘以常数
SC1000

0

如果您使用原型框架,则可以使用数组的intersect方法来找出它们是否相同(无论顺序如何):

var array1 = [1,2];
var array2 = [2,1];

if(array1.intersect(array2).length === array1.length) {
    alert("arrays are the same!");
}

这不起作用- [1,2].intersect([1,2,3]).length === [1,2].length返回true。您也应该比较原始数组的长度,我已经编辑了文章以进行演示。
GMA 2014年

实际上,我刚刚意识到我建议的编辑在重复的情况下不起作用...例如,它将针对array1 = [1,1,2]; array2 = [1,1,2];... 返回false ...对于该输入,原始答案不会失败。
GMA 2014年

您可以使用_.difference(array1, array2).length;
Vic

0

请检查这个答案

var arr1= [12,18];
var arr2= [12, 18, 20, 11, 19, 14, 6, 7, 8, 16, 9, 3, 1, 13, 5, 4, 15, 10, 2, 17];
for(i=0;i<arr1.length;i++)
{
var array1=arr1[i];
for(j=0;j<arr2.length;j++)
{
    var array2=arr2[j];
    if(array1==array2)
    {
return true;
    }
}
}

2
这在功能上等效于此答案,除了几个错误。首先,这应该全部包装在一个函数中,否则return将无效。其次,您应该检查已排序的数组,因为[1,2][2,1]将被检测为不相同。第三,也是最重要的一点,这实际上只会检查某些元素是否相同。有条件的应该是if (array1!==array2) {return false;}。也许这可以在将来对您有所帮助!
卡洛斯·普雷西奥索

1
另外,请尝试使用缩进以更好地理解代码流以及更清晰的变量名。例如:array1并且array2可以重命名为elem1elem2。这两个技巧将在将来为您省去很多麻烦!
卡洛斯·普雷西奥索

2
经进一步检查,为什么要进行双循环?两个数组的长度应相同,否则,它们将直接不相等。这样,您只能使用一个循环。现在,这个代码检查是否任何的第一阵列的元件是任意位置在第二个。检查此答案以查看应如何实施。祝您在JavaScript旅途中一切顺利!
卡洛斯·普雷西奥索

0

经过很长一段时间的回答,但希望这会对寻求简单解决方案和现代新手的人有所帮助。

现在我们可以做到这一点使用多个库,例如lodashunderscore等)(由于简单,多种功能和高使用率,如今这些已成为项目的一部分)

您可以使用lodash库中的交集。

_.intersection(['2-1', '1'], ['2-2', '3-1', '2-1']); 
// => ['2-1']

这将适用于任何数据类型。


0

如果要比较两个数组并检查两个数组中是否有相同的对象,它将起作用。范例:

Array1 = [a,b,c,d]
Array2 = [d,e,f,g]

在这里,“ d”在两个数组中都是通用的,因此此函数将返回真值。

  cehckArray(array1, array2) {
    for (let i = 0; i < array1.length; i++) {
      for (let j = 0; j < array2.length; j++) {
        if (array1[i] === array2[j]) {
          return true;
        }
      }
    }
    // Return if no common element exist 
    return false;
  }


0

根据已接受的答案,我还有另一种方法。

function compareArrays(array1, array2) {

    if (
        !Array.isArray(array1)
        || !Array.isArray(array2)
        || array1.length !== array2.length
    ) return false;

    var first = array1.sort().map(value => (String(value))).join();
    var second = array2.sort().map(value => (String(value))).join();

    return first == second ? true : false;
}

嗨,欢迎来到StackOverflow!尽管此答案在某些情况下可行,但在某些特定情况下却行不通。首先,请注意.sort()会修改原始数组。如今,人们认为卫生状况很差,这就是为什么原始答案首先使用.concat()进行复制的原因。
卡洛斯·普雷西奥索

第二点,这与其他JavaScript不一致。{foo:“ bar”} === {foo:“ bar”}返回false(它们是分别创建的两个不同的对象);因此compareArrays([[{foo:“ bar”}],[{foo:“ bar”}]))也应返回false以保持一致性。但是,对于您的实现,它返回true,因为对象的字符串表示形式相同。这可能是一种理想的行为,或者不是,但是无论如何都要谨记。
卡洛斯·普雷西奥索

0

比较两个数组的功能,以检查两个数组是否具有相同的元素。即使他们出了故障...

这对简单数组很有用。[String,Number,Boolean,null,NaN]。

我不使用.sort(),它修改了原始数组。有人说这是不好的...

警告。此函数是有限的,无法比较对象“ [],{}”或这些数组中的函数,数组本身就是对象。

   let arraysHasSameElements = (arr1, arr2) => {
        let count =
            // returns counting of occurrences.
            (arr, val) => arr.reduce((count, curr) => (curr === val ? 1 : 0) + count, 0);

        /* this will return true if lengths of the arrays is equal.
           then compare them.*/
        return arr1.length === arr2.length

            // compare arr1 against arr2.
            && arr1.reduce((checks, val) =>

                /*  creating array of checking if a value has equal amount of occurrences
                    in both arrays, then adds true 'check'. */
                checks.concat(count(arr1, val) === count(arr2, val)), [])

                // checking if each check is equal to true, then .every() returns true.
                .every(check => check);
    }

    let arr1 = ['',-99,true,NaN,21,null,false,'help',-99,'help',NaN], 
        arr2 = [null,-99,'',NaN,NaN,false,true,-99,'help',21,'help'];
    arraysHasSameElements(arr1, arr2); //true

    let arr3 = [false,false,false,false,false,false], 
        arr4 = [false,false,false,false,false,false]
    arraysHasSameElements(arr3, arr4); //true


    // here we have uncommented version.
    let arraysHasSameElements = (arr1, arr2) => {
        let count = (arr, val) => arr.reduce((count, curr) => (curr === val ? 1:0) + count, 0);
        return arr1.length === arr2.length && arr1.reduce((checks, val) =>
            checks.concat(count(arr1, val) === count(arr2, val)), []).every(check => check);
    }

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.