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

IT技术 javascript arrays object
2021-01-24 12:18:14

我有两个这样的结果集:

// 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" },
]

我需要的最终结果是这些数组之间的差异——最终结果应该是这样的:

[{ value: "4", display: "Ryan" }]

有可能在 JavaScript 中做这样的事情吗?

6个回答

只使用本机 JS,这样的事情会起作用:

const 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"}];
const 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"}];

// A comparer used to determine if two entries are equal.
const isSameUser = (a, b) => a.value == b.value && a.display == b.display;

// Get items that only occur in the left array,
// using the compareFunction to determine equality.
const onlyInLeft = (left, right, compareFunction) => 
  left.filter(leftValue =>
    !right.some(rightValue => 
      compareFunction(leftValue, rightValue)));

const onlyInA = onlyInLeft(a, b, isSameUser);
const onlyInB = onlyInLeft(b, a, isSameUser);

const result = [...onlyInA, ...onlyInB];

console.log(result);

这是有效的,并且可能是最好的直接答案,但是将它变成接受一个谓词和两个列表并通过适当地应用谓词返回两个列表的对称差异的东西会很好。(如果它比必须运行所有 m * n 次比较更有效,则加分!)
2021-03-20 12:18:14
@Cerbrus:是的。谓词是一个返回布尔值(truefalse值)的函数。在这种情况下,如果我们通过要求用户作为函数传递相等性检查来将测试相等性的概念与代码的其余部分分开,我们可以使一个简单的通用算法。
2021-03-22 12:18:14
该比较器为当前数组中的每个项目运行内部函数。所述otherArray.filter返回从项目的阵列otherArray是相同的当前项。如果存在任何此类项目 ( .length > 0),则当前项目在两个数组之间不是唯一的,因此不应从comparer@Whymess返回当前项目
2021-03-28 12:18:14
我喜欢这个答案,太棒了,谢谢
2021-04-08 12:18:14
@ScottSauyet:我花了一段时间才再次找到这个答案,但现在好多了:D
2021-04-09 12:18:14

对于那些喜欢 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);

请解释一下!
2021-03-22 12:18:14
完美运行,谢谢!!
2021-03-23 12:18:14
我喜欢这个解决方案,就像一个魅力!谢谢!!
2021-03-24 12:18:14
不错,谢谢!!
2021-03-29 12:18:14
我喜欢这个解决方案。它创建了一个只有 value 属性的临时对象,所以保持它小
2021-04-05 12:18:14

您可以Array.prototype.filter()Array.prototype.some().

这是一个示例(假设您的数组存储在变量result1和 中result2):

//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);
import differenceBy from 'lodash/differenceBy'

const myDifferences = differenceBy(Result1, Result2, 'value')

这将返回两个对象数组之间的差异,使用键value来比较它们。请注意,不会返回具有相同值的两个东西,因为其他键将被忽略。

这是lodash的一部分

要安装它,您需要将其写成小写:npm i lodash.differenceby. 好消息是这differenceBy(Result1, Result2, 'value')differenceBy(Result2, Result1, 'value')您可以使用一个查看已删除的内容和另一个查看已添加的内容不同。很有用。
2021-03-20 12:18:14
上面的json对象是错误的。尝试这种方式时更改 = for :
2021-03-25 12:18:14

我采用了一种更通用的方法,尽管在想法上与@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"}

与 Cerebrus 的方法相比,它有一个小优势(就像 Kasper Moerch 的方法一样),它可以提前逃脱;如果找到匹配项,则不会检查列表的其余部分。如果我curry手头有一个函数,我会做一些不同的事情,但这工作正常。

解释

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

我们将以下函数传递给makeSymmDiffFunc

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

这个函数是我们决定两个对象相等的方式。像所有返回trueor 的函数一样false,它可以被称为“谓词函数”,但这只是术语。重点是它makeSymmDiffFunc配置了一个函数,该函数接受两个对象,true如果我们认为它们相等false返回,否则返回

使用它,makeSymmDiffFunc(阅读“制作对称差分函数”)返回一个新函数:

        return function(a, b) {
            return complement(pred, a, b).concat(complement(pred, b, a));
        };

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

不过,再看一遍,我绝对可以从您的代码中得到提示,并通过使用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));
        };
    };
}());

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"}
@KasperMoerch:添加了一个冗长的解释。我希望这有帮助。(这也让我认识到这段代码应该进行认真的清理。)
2021-03-24 12:18:14
你能在你的代码中添加更多的解释吗?我不确定 JavaScript 初学者是否会理解谓词方法的工作原理。
2021-04-06 12:18:14