我有两个对象数组:
var a = [ {'id': 20}, {'id': 15}, {'id': 10}, {'id': 17}, {'id': 23} ];
var b = [ {'id': 90}, {'id': 15}, {'id': 17}, {'id': 23} ];
我想获取a中的对象,但b中不存在的对象。此示例的结果将是:
{'id': 20}
和 {'id': 10}
。
因为数组可能很大,所以我需要一种有效的方法来做到这一点。
// Make hashtable of ids in B
var bIds = {}
b.forEach(function(obj){
bIds[obj.id] = obj;
});
// Return all elements in A, unless in B
return a.filter(function(obj){
return !(obj.id in bIds);
});
非常小的附录:如果列表非常大并且您希望避免 2 倍额外内存,您可以首先将对象存储在哈希图中而不是使用列表,假设 id 是唯一的:
a = {20:{etc:...}, 15:{etc:...}, 10:{etc:...}, 17:{etc:...}, 23:{etc:...}}
。我个人会这样做。或者:其次,javascript 对列表进行就地排序,因此不会使用更多内存。例如a.sort((x,y)=>x.id-y.id)
排序会比上面的更糟糕,因为它是 O(N log(N))。但是,如果您无论如何都必须对其进行排序,则存在一种涉及两个排序列表的 O(N) 算法:即,您将两个列表一起考虑,并重复从列表中取出最左边(最小)的元素(即检查,然后递增)您所取列表中的指针/书签)。这就像合并排序一样,但要更加小心地找到相同的项目......并且可能对编码来说很麻烦。第三,如果列表是遗留代码,并且您希望将其转换为哈希图而不需要内存开销,您也可以通过重复将元素从列表中弹出并放入哈希图中来逐个元素地执行此操作。
在 lodash 4.12.0 中,您可以使用 _.differenceBy。
_.differenceBy(a, b, 'id');
执行此操作的一般方法是:
现在很多编程环境都有 set 和/或 HashSet 实现,这使得执行此操作变得非常简单。
在特殊情况下,其他方式可能会更有效。例如,如果您的元素是字节大小的值,并且 a 和 b 都相当大,那么我将使用包含 256 个元素的布尔数组“flags”,将所有元素初始化为 false。然后,对于 b 的每个元素 x,将 flags[x] 设置为 true。然后迭代 a,对于 a 中的每个 y,检查是否设置了 flags[y]。
如果你不反对包含一个库,请使用 underscore.js 它有一个很好的交集函数 http://documentcloud.github.com/underscore/
如果我们只想比较 id,则接受的答案有效。如果你想比较整个对象,我们可以使用:
_.differenceBy(a, b, JSON.stringify);