如何在JavaScript中获取两个对象数组之间的差异

BKM*_*BKM 81 javascript arrays object

我有两个这样的结果集:

// Result 1
[
    { value="0", display="Jamsheer" },
    { value="1", display="Muhammed" },
    { value="2", display="Ravi" },
    { value="3", display="Ajmal" },
    { value="4", display="Ryan" }
]

// Result 2
[
    { value="0", display="Jamsheer" },
    { value="1", display="Muhammed" },
    { value="2", display="Ravi" },
    { value="3", display="Ajmal" },
]
Run Code Online (Sandbox Code Playgroud)

我需要的最终结果是这些数组之间的区别 - 最终结果应该是这样的:

[{ value="4", display="Ryan" }]
Run Code Online (Sandbox Code Playgroud)

是否可以在JavaScript中执行此类操作?

Cer*_*rus 118

仅使用本机JS,这样的东西将起作用:

a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"},  { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]
b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]

function comparer(otherArray){
  return function(current){
    return otherArray.filter(function(other){
      return other.value == current.value && other.display == current.display
    }).length == 0;
  }
}

var onlyInA = a.filter(comparer(b));
var onlyInB = b.filter(comparer(a));

result = onlyInA.concat(onlyInB);

console.log(result);
Run Code Online (Sandbox Code Playgroud)

  • 这是可行的,并且可能是最好的直接答案,但最好将其变成接受谓词和两个列表并通过适当应用谓词返回两个列表的对称差的东西。(如果比必须运行所有 m * n 比较两次更有效,则加分!) (2认同)
  • @Cerbrus:是的.谓词是一个返回布尔值('true`或`false`值.)的函数.在这种情况下,如果我们通过要求用户将相等性检查作为传递来将相等的测试概念与其余代码分开.一个函数,我们可以做一个简单的通用算法. (2认同)

kas*_*rch 58

你可以Array.prototype.filter()结合使用Array.prototype.some().

这里是(假设你的数组存储在变量的例子result1result2):

//Find values that are in result1 but not in result2
var uniqueResultOne = result1.filter(function(obj) {
    return !result2.some(function(obj2) {
        return obj.value == obj2.value;
    });
});

//Find values that are in result2 but not in result1
var uniqueResultTwo = result2.filter(function(obj) {
    return !result1.some(function(obj2) {
        return obj.value == obj2.value;
    });
});

//Combine the two arrays of unique entries
var result = uniqueResultOne.concat(uniqueResultTwo);
Run Code Online (Sandbox Code Playgroud)


Sco*_*yet 15

我采用了一种更为通用的方法,尽管与@Cerbrus@Kasper Moerch的方法相似.我创建了一个接受谓词的函数来确定两个对象是否相等(这里我们忽略 $$hashKey属性,但它可以是任何东西)并返回一个函数,该函数根据该谓词计算两个列表的对称差异:

a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"},  { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}]
b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}]

var makeSymmDiffFunc = (function() {
    var contains = function(pred, a, list) {
        var idx = -1, len = list.length;
        while (++idx < len) {if (pred(a, list[idx])) {return true;}}
        return false;
    };
    var complement = function(pred, a, b) {
        return a.filter(function(elem) {return !contains(pred, elem, b);});
    };
    return function(pred) {
        return function(a, b) {
            return complement(pred, a, b).concat(complement(pred, b, a));
        };
    };
}());

var myDiff = makeSymmDiffFunc(function(x, y) {
    return x.value === y.value && x.display === y.display;
});

var result = myDiff(a, b); //=>  {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}
Run Code Online (Sandbox Code Playgroud)

与Cerebrus的方法相比,它有一个小优势(Kasper Moerch的方法也是如此),因为它很早就逃脱了; 如果找到匹配,则不会检查列表的其余部分.如果我有一个curry方便的功能,我会这样做有点不同,但这工作正常.

说明

评论要求为初学者提供更详细的解释.这是一次尝试.

我们将以下函数传递给makeSymmDiffFunc:

function(x, y) {
    return x.value === y.value && x.display === y.display;
}
Run Code Online (Sandbox Code Playgroud)

这个函数就是我们判断两个对象是否相等的方法.像返回的所有功能true或者false,它可以被称为"断言功能",但是这只是术语.重点是makeSymmDiffFunc配置了一个接受两个对象的函数,true如果我们认为它们相等false则返回,如果我们不相等.

使用它,makeSymmDiffFunc(读取"make symmetric difference function")返回一个新函数:

        return function(a, b) {
            return complement(pred, a, b).concat(complement(pred, b, a));
        };
Run Code Online (Sandbox Code Playgroud)

这是我们实际使用的功能.我们传递两个列表,它找到第一个不在第二个中的元素,然后在第二个中不在第一个中的元素并组合这两个列表.

但是,再看一遍,我绝对可以从你的代码中获得一些提示并通过使用简化主要功能some:

var makeSymmDiffFunc = (function() {
    var complement = function(pred, a, b) {
        return a.filter(function(x) {
            return !b.some(function(y) {return pred(x, y);});
        });
    };
    return function(pred) {
        return function(a, b) {
            return complement(pred, a, b).concat(complement(pred, b, a));
        };
    };
}());
Run Code Online (Sandbox Code Playgroud)

complement使用谓词并返回其第一个列表中不在其第二个列表中的元素.这比我第一次使用单独的contains函数更简单.

最后,main函数包含在一个立即调用的函数表达式(IIFE)中,以使内部complement函数不在全局范围内.


几年后更新

既然ES2015已经变得无处不在,我建议使用相同的技术,并且更少的样板:

const diffBy = (pred) => (a, b) => a.filter(x => !b.some(y => pred(x, y)))
const makeSymmDiffFunc = (pred) => (a, b) => diffBy(pred)(a, b).concat(diffBy(pred)(b, a))

const myDiff = makeSymmDiffFunc((x, y) => x.value === y.value && x.display === y.display)

const result = myDiff(a, b)
//=>  {value="a63a6f77-c637-454e-abf2-dfb9b543af6c", display="Ryan"}
Run Code Online (Sandbox Code Playgroud)

  • 你能在你的代码中添加更多的解释吗?我不确定 JavaScript 初学者是否会理解谓词方法的工作原理。 (2认同)

小智 10

对于那些喜欢ES6中的一线解决方案的人,这样的事情:

const arrayOne = [ 
  { value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer" },
  { value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed" },
  { value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi" },
  { value: "e97339e1-939d-47ab-974c-1b68c9cfb536", display: "Ajmal" },
  { value: "a63a6f77-c637-454e-abf2-dfb9b543af6c", display: "Ryan" },
];
          
const arrayTwo = [
  { value: "4a55eff3-1e0d-4a81-9105-3ddd7521d642", display: "Jamsheer"},
  { value: "644838b3-604d-4899-8b78-09e4799f586f", display: "Muhammed"},
  { value: "b6ee537a-375c-45bd-b9d4-4dd84a75041d", display: "Ravi"},
  { value: "e97339e1-939d-47ab-974c-1b68c9cfb536", display: "Ajmal"},
];

const results = arrayOne.filter(({ value: id1 }) => !arrayTwo.some(({ value: id2 }) => id2 === id1));

console.log(results);
Run Code Online (Sandbox Code Playgroud)

  • 请解释一下! (7认同)
  • 不适用于所有情况,仅从第一个对象返回唯一对象。 (3认同)
  • 如果不同的对象位于第二个数组中,则此方法不起作用 (3认同)

小智 7

我使用过滤器和一些东西找到了这个解决方案。

resultFilter = (firstArray, secondArray) => {
  return firstArray.filter(firstArrayItem =>
    !secondArray.some(
      secondArrayItem => firstArrayItem._user === secondArrayItem._user
    )
  );
};
Run Code Online (Sandbox Code Playgroud)


小智 6

我认为@Cerbrus 解决方案是正确的。我已经实现了相同的解决方案,但将重复的代码提取到它自己的函数中(DRY)。

 function filterByDifference(array1, array2, compareField) {
  var onlyInA = differenceInFirstArray(array1, array2, compareField);
  var onlyInb = differenceInFirstArray(array2, array1, compareField);
  return onlyInA.concat(onlyInb);
}

function differenceInFirstArray(array1, array2, compareField) {
  return array1.filter(function (current) {
    return array2.filter(function (current_b) {
        return current_b[compareField] === current[compareField];
      }).length == 0;
  });
}
Run Code Online (Sandbox Code Playgroud)


Noa*_*oah 6

import differenceBy from 'lodash/differenceBy'

const myDifferences = differenceBy(Result1, Result2, 'value')
Run Code Online (Sandbox Code Playgroud)

这将返回两个对象数组之间的差异,并使用键value进行比较。注意,具有相同值的两件事将不会返回,因为其他键将被忽略。

这是lodash的一部分。


Nik*_*wal 6

您可以创建一个具有键的对象,该键是数组中每个对象对应的唯一值,然后根据其他对象中键的存在来过滤每个数组。它降低了操作的复杂性。

ES6

let a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"},  { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}];
let b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}];

let valuesA = a.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let valuesB = b.reduce((a,{value}) => Object.assign(a, {[value]:value}), {});
let result = [...a.filter(({value}) => !valuesB[value]), ...b.filter(({value}) => !valuesA[value])];
console.log(result);
Run Code Online (Sandbox Code Playgroud)

ES5

var a = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal"},  { value:"a63a6f77-c637-454e-abf2-dfb9b543af6c", display:"Ryan"}];
var b = [{ value:"4a55eff3-1e0d-4a81-9105-3ddd7521d642", display:"Jamsheer", $$hashKey:"008"}, { value:"644838b3-604d-4899-8b78-09e4799f586f", display:"Muhammed", $$hashKey:"009"}, { value:"b6ee537a-375c-45bd-b9d4-4dd84a75041d", display:"Ravi", $$hashKey:"00A"}, { value:"e97339e1-939d-47ab-974c-1b68c9cfb536", display:"Ajmal", $$hashKey:"00B"}];

var valuesA = a.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var valuesB = b.reduce(function(a,c){a[c.value] = c.value; return a; }, {});
var result = a.filter(function(c){ return !valuesB[c.value]}).concat(b.filter(function(c){ return !valuesA[c.value]}));
console.log(result);
Run Code Online (Sandbox Code Playgroud)


lem*_*spy 6

您可以对 b 执行 diff a 并在 a 上执行 diff b ,然后合并两个结果

let a = [
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" },
    { value: "4", display: "Ryan" }
]

let b = [
    { value: "0", display: "Jamsheer" },
    { value: "1", display: "Muhammed" },
    { value: "2", display: "Ravi" },
    { value: "3", display: "Ajmal" }
]

// b diff a
let resultA = b.filter(elm => !a.map(elm => JSON.stringify(elm)).includes(JSON.stringify(elm)));

// a diff b
let resultB = a.filter(elm => !b.map(elm => JSON.stringify(elm)).includes(JSON.stringify(elm)));  

// show merge 
console.log([...resultA, ...resultB]);
Run Code Online (Sandbox Code Playgroud)


Maj*_*man 5

另外,说两个不同的对象数组 key value

// Array Object 1
const arrayObjOne = [
    { userId: "1", display: "Jamsheer" },
    { userId: "2", display: "Muhammed" },
    { userId: "3", display: "Ravi" },
    { userId: "4", display: "Ajmal" },
    { userId: "5", display: "Ryan" }
]

// Array Object 2
const arrayObjTwo =[
    { empId: "1", display: "Jamsheer", designation:"Jr. Officer" },
    { empId: "2", display: "Muhammed", designation:"Jr. Officer" },
    { empId: "3", display: "Ravi", designation:"Sr. Officer" },
    { empId: "4", display: "Ajmal", designation:"Ast. Manager" },
]
Run Code Online (Sandbox Code Playgroud)

您可以使用filterines5native js来减去两个数组对象。

//Find data that are in arrayObjOne but not in arrayObjTwo
var uniqueResultArrayObjOne = arrayObjOne.filter(function(objOne) {
    return !arrayObjTwo.some(function(objTwo) {
        return objOne.userId == objTwo.empId;
    });
});
Run Code Online (Sandbox Code Playgroud)

ES6你可以使用箭头函数对象解构ES6

const ResultArrayObjOne = arrayObjOne.filter(({ userId: userId }) => !arrayObjTwo.some(({ empId: empId }) => empId === userId));

console.log(ResultArrayObjOne);
Run Code Online (Sandbox Code Playgroud)