比较对象数组而不考虑顺序

5
我有两个对象数组需要进行比较,但是它们的顺序不重要。我不能对它们进行排序,因为我没有它们的键名,因为函数必须是通用的。关于这个数组唯一的信息是,两个数组对象具有相同数量的键,并且这些键的名称相同。所以array1必须包含与array2相同的对象。
var array1 = [{"key1":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
var array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];

在这个例子中,array1必须等于array2。我尝试使用chai的.eql()方法,但它没有起作用。

“比较它们”是什么意思?你只需要知道它们是否相同吗?需要一个布尔响应吗? - Alec Fenichel
所有的值都是字符串类型吗? - komron
3个回答

7
以下解决方案:
  • 将验证数组具有相等数量的元素
  • 不对键施加限制(例如:不包含某个分隔符)
  • 要求键和(字符串)值都相同
  • 时间复杂度为O(nlogn)(而不是其他一些解决方案的O(n²)

function equalArrays(a, b) {
    if (a.length !== b.length) return false;
    const ser = o => JSON.stringify(Object.keys(o).sort().map( k => [k, o[k]] ));
    a = new Set(a.map(ser));
    return b.every( o => a.has(ser(o)) );
}

// Example
var array1 = [{"key1":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
var array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];
console.log(equalArrays(array1, array2)); // true
// Example with different key name
var array1 = [{"key0":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
var array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];
console.log(equalArrays(array1, array2)); // false


1
你可以使用一个分隔符将对象的每个值连接起来,然后生成一个新的字符串数组,再使用array#every和array#includes比较每个值。

var array1 = [{"key1":"Banana", "key2":"Yammy"}, {"key1":"Broccoli", "key2":"Ew"}];
    array2 = [{"key1":"Broccoli", "key2":"Ew"}, {"key1":"Banana", "key2":"Yammy"}];
    values = (o) => Object.keys(o).sort().map(k => o[k]).join('|'),
    mapped1 = array1.map(o => values(o)),
    mapped2 = array2.map(o => values(o));

var res = mapped1.every(v => mapped2.includes(v));

console.log(res);


1
当一个数组有比另一个数组更多的条目时,当一个键有管道符号时,当对象具有不同的键时,这可能会失败... - trincot
它运行得非常顺利。有一种简单的方法可以打印对象数组,但不匹配吗?例如,如果其中一个数组中有“香蕉”而不是“香蕉”。 - Brian Batista
@trincot,我在比较对象之前验证数组的长度。 - Brian Batista
错误结果的示例:将第一个“key1”更改为“key0”:结果仍然为true。或者,删除“key2”:“Yammy”,并将“Banana”更改为“Banana | Yammy”:结果仍然为true。 - trincot
@trincot 你说得对,但问题提到“我将拥有关于数组的唯一信息是,两个数组对象具有相同数量的键,并且这些键具有相同的名称。” - Hassan Imam
然而,你仍然可以将值Banana|YammyNiceBananaYammy|Nice进行比较,并且它们是相等的。此外,运行时间为*O(n²)*。 - trincot

0
你可以像下面这样做:
对于每个数组中的每个对象,您可以计算其表示:
arr1.forEach( (obj) => {
    obj.representation = '';
    for (let key of Object.keys(obj)) {
      obj.representation += obj[key];
    }
}

对于arr2同样适用。

现在,您可以按照表示方式对两个数组进行排序,然后进行比较。

要进行排序,请执行以下操作:

arr1.sort( (a,b) => { return a.representation > b.representation } );
arr2.sort( (a,b) => { return a.representation > b.representation } );

排序后,您可以比较两个数组

let equal = arr1.every( (el, i) => arr2[i]===el );

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