检查一个数组是否存在于一个数组的数组中?

42

我正在使用JavaScript,并希望检查一个数组是否存在于一个数组中的数组中。

以下是我的代码,以及返回值:

var myArr = [1,3];
var prizes = [[1,3],[1,4]];
prizes.indexOf(myArr);
-1

为什么?

在jQuery中也是一样的:

$.inArray(myArr, prizes);
-1

当元素存在于数组中时,为什么这会返回-1?


请看这个例子:http://jsfiddle.net/DUTTw/ - insertusernamehere
你不能使用等号操作符来比较两个唯一的对象,你需要进行深度平等检查。一些库提供了这样的功能,或者在这里我组合了一个,你可能会觉得有用。 - Xotic750
11个回答

48

你可以使用这个

 var a = [ [1,2] , [3,4] ];
 var b = [1,2];
 a = JSON.stringify(a);
 b = JSON.stringify(b);

然后您可以使用indexOf()方法检查其是否存在

var c = a.indexOf(b);
if(c != -1){
    console.log('element present');
}

1
@Pirijan 如果这个能够工作的话,那就真的很优雅了,但是它并没有工作(https://jsfiddle.net/md3k8ewc/),`JSON.stringify(a)` 返回 [null] 然后检查失败了。 - Charles Clayton
1
@crclayton,两个数组之间应该有一个逗号,我猜在发布答案时犯了一个错误,现在应该可以工作了。 - ajack13
2
虽然来晚了一点,但这确实是一种优美的做法,绝对应该成为被采纳的答案,因为它的简洁明了。 - ryanovas
我有点晚了,但如果a是像[[[1,2]],[3,4]]这样的东西,这仍然可以工作,但这不是预期的结果。 - Tyrcnex

21

由于对象只有在引用同一对象时才相等,因此 [1,3] !== [1,3]。您需要编写自己的搜索程序:

function searchForArray(haystack, needle){
  var i, j, current;
  for(i = 0; i < haystack.length; ++i){
    if(needle.length === haystack[i].length){
      current = haystack[i];
      for(j = 0; j < needle.length && needle[j] === current[j]; ++j);
      if(j === needle.length)
        return i;
    }
  }
  return -1;
}

var arr = [[1,3],[1,2]];
var n   = [1,3];

console.log(searchForArray(arr,n)); // 0

参考资料

  • 使用相等运算符:

    如果两个操作数都是对象,则将它们作为对象进行比较,仅当两者引用同一对象时,相等测试才为真。


for(var i in haystack ){ 相较于 for(i = 0; i < haystack.length; ++i){,如果 haystack[1] 不存在但 haystack[0]haystack[2] 已定义,仍不会抛出异常 - 如果匹配到 needle 则返回 i=2 - Bharath Parlapalli
如果haystack[1]缺失,那么haystack不是一个有效的数组,因此也不适合作为searchForArray的候选对象。 - Zeta
1
在控制台中测试"[1,3] == [1,3]"... 什么鬼。 - Charles Clayton
1
这个 for 循环的快捷方式在大多数 ESLint 配置中都会失败。 - dude

14
你可以使用 Array#some 迭代二维数组,并且使用 Array#every 检查每个内部数组的所有项是否与单个数组匹配。

var array = [1, 3],
    prizes = [[1, 3], [1, 4]],
    includes = prizes.some(a => array.every((v, i) => v === a[i]));

console.log(includes);


1
这是一个不错的方法!但是请注意,如果array的长度为0,则它总是会返回true,我想你不希望得到这样的结果。所以,在使用array.every(...之前,你应该添加array.length && - Nebulosar

5
因为这两种方法在处理对象时使用引用相等性。存在的数组和您要搜索的数组可能在结构上完全相同,但它们是唯一的对象,因此它们不会被比较为相等。
即使在实践中没有用处,这将给出预期的结果:
var myArr = [1,3];
var prizes = [myArr,[1,4]];
prizes.indexOf(myArr);

为了完成你想要的操作,你需要编写代码来递归地比较数组的内容。

2
function checkArrayInArray(arr, farr){
    if(JSON.stringify(arr).includes(JSON.stringify(farr))) return true;
    return false;
}

1

首先为数组定义一个比较函数

// attach the .compare method to Array's prototype to call it on any array
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;

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

第二步,只需找到包含

的数组。
prizes.filter(function(a){ return a.compare(myArr)})

注意:检查array.filter的浏览器兼容性。


1
由于JavaScript对象是按标识而不是按值进行比较的,因此如果它们没有引用相同的对象,则会返回false。
为了使其正常工作,您需要进行递归比较。

1

虽然不是JavaScript专家,但我刚刚发现可以使用Array.everyArray.some来完成此操作。

要查找匹配项的索引:

let anarr = ['a',1, 2]
let arrofarrs = [['a',1, 2], [2,3,4]]

arrofarrs.map(
  subarr => subarr.every(
    (arr_elem, ind) => arr_elem == anarr[ind]
  )
)

// output
// Array [ true, false ]

如果要检查数组是否包含子数组,则只需将map更改为some即可检查true/false

arrofarrs.some(
  subarr => subarr.every(
    (arr_elem, ind) => arr_elem == anarr[ind]
  )
)
// output
// true

当然,这只适用于单层嵌套,但可以进行递归修饰 ;)


0
function doesArrayOfArraysContainArray (arrayOfArrays, array){
  var aOA = arrayOfArrays.map(function(arr) {
      return arr.slice();
  });
  var a = array.slice(0);
  for(let i=0; i<aOA.length; i++){
    if(aOA[i].sort().join(',') === a.sort().join(',')){
      return true;
    }
  }
  return false;
}

值得注意的是:
  • aOA[i].sort().join(',') === a.sort().join(',') 是一种有用的方法,用于检查包含相同值且顺序相同但是引用不同对象的数组。

  • array.slice(0) 创建原始二维数组的非引用副本。

  • 然而,要创建三维数组的副本 arrayOfArrays.slice(0) 不起作用;引用链仍将存在。为了创建非引用副本,需要使用 .map 函数。

如果您不创建这些非引用数组副本,您可能会遇到一些难以跟踪的问题。此函数应作为条件运算符运行,而不影响传入的初始对象。

Javascript 是一个善变的女士。


0

假设您只处理二维数组(您提到了“数组的数组”,但没有更深入的内容),这个非递归代码应该可以满足您的需求。

var compare_arrays = function (array_a, array_b) {
    var rtn = true,
        i, l;
    if (array_a.length === array_b.length) {
        for (i = 0, l = array_a.length; (i < l) && rtn; i += 1) {
            rtn = array_a[i] === array_b[i];
        }
    } else {
        rtn = false;
    }
    return rtn;
},
indexOfSimilarArray = function (arrayToFind, arrayToSearch) {
    var i = arrayToSearch.length,
        chk = false;
    while (i && !chk) {
        i -= 1;
        chk = compare_arrays(arrayToFind, arrayToSearch[i]);
    }
    return i;
};

// Test
var myArr = [1,3];
var prizes = [[1,3],[1,4]];
indexOfSimilarArray(myArr, prizes);

JSFiddle: http://jsfiddle.net/guypursey/V7XpE/。(查看控制台以查看结果。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接