在Javascript中比较两个数组

11

我在Javascript中有两个数组,目前看起来像这样,但是它们会被HTTP请求(node)更新:

var x = [[292,"2349","902103","9"],[3289,"93829","092","920238"]]
var y = [[292,"2349","902103","9"],[322,"93829","092","920238"],[924,"9320","8932","4329"]]

我想比较这些数组,如果y中有一个数组不在x中,它将被保存到一个新数组z中。请注意,有时数组内部的数组顺序会改变,但我不希望这影响结果。
然而,如果x中有一个数组不在y中,则不应将其保存到z中。
我阅读了JavaScript array difference并成功复制了它,但是如果x数组未显示在y中,它会被打印到z中。我想知道是否可能不存储它,只存储y中不同的项?

内部数组是否总是包含字符串和数字? - elad.chen
它们将始终以此格式出现(始终按相同顺序):[int,“str”,“str”,“str”]。 - GregW
整数需要不同吗?这样就够了吗? - omarjmh
1
可能是如何在JavaScript中比较数组?的重复问题。 - The Reason
1
这不是重复的问题。如何在JavaScript中比较数组? 这个问题询问的是仅包含原始类型(如数字或字符串)的数组的比较,而这个问题询问的是包含其他数组的数组的比较。 - Michał Perłakowski
显示剩余3条评论
6个回答

9

使用高阶函数接受一个数组(随着每次 y 的迭代而更改)并返回一个新函数,该函数操作 some 中的每个元素(嵌套数组)。如果这些数组包含相同的元素但顺序不同,则返回 true

function matches(outer) {
  return function (el) {
    if (outer.length !== el.length) return false;
    return el.every(function (x) {
      return outer.indexOf(x) > -1;
    });
  }
}

遍历 y 并返回不在 x 中的数组列表。

function finder(x, y) {
  return y.filter(function (el) {
    return !x.some(matches(el));
  });
}

finder(x, y);

DEMO


finder 中的 .reduce.filter 有什么不同吗? - andyk
这可能不会影响到原帖作者的使用场景,但是你的 matches 函数会认为两个不同顺序但包含相同元素的子数组匹配:matches([1, '2', '3'])(['3', 1, '2']) === true。它也会认为如果第一个数组有额外的元素仍然匹配成功:matches([1, 4, '2', '3', 5, '6'])(['3', 1, '2']) === true - Noah Freitas
不用担心第一个问题,因为楼主在评论中澄清了。但你的第二个观点是正确的,我已经更新了我的代码以反映这一点,感谢@NoahFreitas。 - Andy
您也可以使用 Array.prototype.includes() 来确定数组是否包含特定的元素,而不是使用 .indexOf() - Michał Perłakowski
@GregW,不是这样的。看看演示-它返回一系列结果的数组。 - Andy
显示剩余2条评论

3
你可以使用这个函数arrayDiff。它接受两个数组(A和B),并返回第一个数组中不在第二个数组中的所有元素(A \ B),并删除任何重复项。如果两个数组元素的JSON序列化相同,则它们是相等的。
var x = [[292,"2349","902103","9"],[3289,"93829","092","920238"]];
var y = [[292,"2349","902103","9"],[322,"93829","092","920238"],[924,"9320","8932","4329"]];

var z = arrayDiff(y, x);

// z is [[322,"93829","092","920238"],[924,"9320","8932","4329"]]

// arrayDiff :: [a], [a] -> [a]
function arrayDiff(a1, a2) {
    let a1Set = toStringSet(a1),
        a2Set = toStringSet(a2);

    return Array.from(a1Set)
                .filter(jsonStr => !a2Set.has(jsonStr))
                .map(JSON.parse);

    // toStringSet :: [a] -> Set<String>
    function toStringSet(arr) {
        return new Set(arr.map(JSON.stringify));
    }
}

2

即使内部数组的顺序不同,也应该起作用。
我假设在其中只有数字和字符串,并且您不希望它们之间进行严格比较。

var x = [[292,"2349","902103","9"],[3289,"93829","092","920238"]];
var y = [[292,"2349","902103","9"],[322,"93829","092","920238"],[924,"9320","8932","4329"]];

// this will do y \ x
var z = arrDiff(y, x);
console.log(z);


function arrDiff(arr1, arr2) {
  var rez = [];

  for (var i = 0; i < arr1.length; i++) {
    if ( ! contains(arr2, arr1[i])) {
      rez.push(arr1[i]);
    }
  }

  return rez;
}

function contains(arr, x) {
  x = x.slice().sort().toString();
  for (var i = 0; i < arr.length; i++) {
    // compare current item with the one we are searching for        
    if (x === arr[i].slice().sort().toString()) {
      return true;
    }
  }

  return false;
}

1

试试这个:

function getArraysDiff(arr1, arr2) {
   var x = arr1.map(function(a) { return a.join("") });
   var y = arr2.map(function(a) { return a.join("") });
   var z = [];

   for ( var i = 0, l = arr1.length; i < l; i++ ) {
      if ( y.indexOf(x[i]) == -1 ) {
        z.push(arr1[i])
      }
   }

   return z;
}

或者这个:
x.filter((function(y) {
    return function(x) {
        return y.indexOf(x.join("")) > -1;
    }
}( y.map(function(y) { return y.join("") }) )))

如果内部数组的排序顺序不能保证在两侧相同,该怎么办? - fahadash
@GregW您能否澄清订单是否有保障? - elad.chen
@fahadash 我猜他可以在 join 之前做一个 .sort()。 - Mihai Vilcu
2
这里认为x = [[292, 2349]], y = [[2922, 349]]是相等的......使用join很糟糕。 - Emissary
2
它们并不相等 - 这就是问题所在 - 但是你的算法会假设它们相等,因为内部数组在连接时都会评估为“2922349”。 - Emissary
显示剩余3条评论

1
你可以使用 Array.prototype.forEach(), Array.prototype.every(), Array.prototype.map(), Array.prototype.indexOf(), JSON.stringify(), JSON.parse()
var z = [];
y.forEach(function(val, key) {
  var curr = JSON.stringify(val);
  var match = x.every(function(v, k) {
    return JSON.stringify(v) !== curr
  });
  if (match && z.indexOf(curr) == -1) z.push(curr)
});

z = z.map(JSON.parse);

var x = [
  [292, "2349", "902103", "9"],
  [3289, "93829", "092", "920238"]
];
var y = [
  [292, "2349", "902103", "9"],
  [322, "93829", "092", "920238"],
  [924, "9320", "8932", "4329"]
];

var z = [];
y.forEach(function(val, key) {
  var curr = JSON.stringify(val);
  var match = x.every(function(v, k) {
    return JSON.stringify(v) !== curr
  });
  if (match && z.indexOf(curr) == -1) z.push(curr)
});

z = z.map(JSON.parse);

console.log(z);

document.querySelector("pre").textContent = JSON.stringify(z, null, 2)
<pre></pre>


1
您有两个数组:

var x = [[292,"2349","902103","9"],[3289,"93829","092","920238"]];
var y = [[292,"2349","902103","9"],[322,"93829","092","920238"],[924,"9320","8932","4329"]];

为了创建Z数组,您需要使用以下函数:
function createZ(){
  var i,j,k=0,z=[],p=x;
  for(j=0;j<y.length;j++){
    for(i=0;i<p.length;i++){
      if(y[j][0]===p[i][0] && y[j][1]===p[i][1] && y[j][2]===p[i][2] && y[j][3]===p[i][3]){
        p.splice(i,1); break;
      } else {
        z[k++]=y[j]; console.log((y[j][0]===p[i][0])+" "+i+","+j);
      }
    }
  }
  return z;
}

注意,createZ()还会将相应条目的i,j打印到控制台。

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