在Javascript中比较未排序的对象数组

4

我需要比较两个未排序的对象数组,例如下面的代码应该返回true:

compareObjs(
    [{ foo: 'foo', bar: 'bar' }, { baz: 'baz' }], 
    [{ baz: 'baz' }, { foo: 'foo', bar: 'bar' }]
)

我知道已经有很多关于比较对象数组的答案,但我并没有找到一个清晰的答案来比较未排序版本的数组。


2
function compareObjs() { return true }会实现这个操作。你为什么期望它返回true?以及在什么情况下它不应该返回true? - Bergi
1
我期望它是正确的,因为两个数组的长度相同且它们包含相同的对象(相同的键和值)。在这种情况下,对象引用并不重要。 - Shota
这里有几个问题是相同的。请查看以下链接:https://dev59.com/l2DVa4cB1Zd3GeqPay-F和https://dev59.com/xXVC5IYBdhLWcg3wtzut#3198202 - xpqz
1
@Shota,你能给它们排序一下吗? - Bergi
我已经阅读了那些答案,但是JSON.stringify不起作用,因为数组没有排序,我不能使用lodash,我必须在Vanilla JS中完成这个任务。 - Shota
显示剩余2条评论
6个回答

2
这里还有另一种可能性:
const array2 = [1,3,2,4,5];

const isInArray1 = array1.every(item => array2.find(item2 => item===item2))
const isInArray2 = array2.every(item => array1.find(item2 => item===item2))

const isSameArray = array1.length === array2.length && isInArray1 && isInArray2

console.log(isSameArray); //true

这对于对象无效,而对于原始类型可以通过使用.includes()代替.find()进行改进。 - GarethAS

0
你可以使用JSON.stringify()将每个对象转换为字符串。然后对这些数组进行排序。并比较每一对。

If you dont't mind about es6:

let arr1 = [{ foo: 'foo', bar: 'bar' }, { baz: 'baz' }];
let arr2 = [{ baz: 'baz' }, { foo: 'foo', bar: 'bar' }];

const Compare = (arr1, arr2) => {
  if (arr1.length != arr2.length) {
    return false
  }

  let a1 = arr1.map(e => JSON.stringify(e)).sort()
  let a2 = arr2.map(e => JSON.stringify(e)).sort()
  
  return !a1.map((e, i) => e == a2[i]).includes(false)
}

console.log(Compare(arr1, arr2))


0

function givemeSanitizedObject(arr1) {
  let obj = {}
  arr1.forEach(function(element, index, array) {
      obj = {
        ...obj,
        ...element,
      }
  })
  return obj
 }

 function compareObjs(arr1, arr2) {
    let obj1 = givemeSanitizedObject(arr1)
    let obj2 = givemeSanitizedObject(arr2)

    for (var property in obj1) {
      if (Object.hasOwnProperty(property)) {
        if (obj1.property !== obj2.property) {
          return false
        }
      }
    }
    return true
}

console.log(compareObjs(
  [{
    foo: 'foo',
    bar: 'bar'
  }, {
    baz: 'baz'
  }], [{
    baz: 'baz'
  }, {
    foo: 'foo',
    bar: 'bar'
  }]
))


很遗憾,这个不起作用:您没有保留每个对象的结构。请在这里查看,这是带有两个明显不同数组的代码:https://jsfiddle.net/1myf4cvk/ - Gerardo Furtado
是的,我认为他有不同的用例。我现在看到了。 - simbathesailor
giveMeSanitisedObject 中,你应该使用 reduce 而不是 forEach。同时,你需要使用 [property] 而不是 .property - Bergi

0
一个基本的方法是循环遍历其中一个数组的所有对象,看看能否在另一个数组中找到相似的对象。
以下是一个示例:

function compareArrays(arr1, arr2){
    if(arr1.length != arr2.length){
        return false;
    }

    for(var i = 0; i < arr1.length; i++){
        var value1 = arr1[i];
        var keys1 = Object.keys(value1);
        var found = false;
        for(var j = 0; j < arr2.length; j++){
           var value2 = arr2[j];
           var keys2 = Object.keys(value2);
           if(keys1.length == keys2.length 
              && keys1.every(k => keys2.includes(k)) 
              && keys1.every(k => value1[k] == value2[k])){
              found = true;
              break;
           }
        }
        if(!found){
           return false;
        }
    }
   
    return true;
}

var comp = compareArrays(
    [{ foo: 'foo', bar: 'bar' }, { baz: 'baz'}], 
    [{ baz: 'baz' }, { foo: 'foo', bar: 'bar'}]
);

console.log(comp);


0
你可以使用哈希表,检查属性和值是否相同。它适用于给定类型。

function compareArrays(array1, array2) {
    var hash = {};

    if (array1.length !== array2.length) {
        return false;
    }

    array1.forEach(function (o) {
        var keys = Object.keys(o).sort(),
            key = keys.join('|'),
            value = keys.map(function (k) { return o[k]; }).join('|');

        hash[key] = hash[key] || {};
        hash[key][value] = (hash[key][value] || 0) + 1;
    });

    return array2.every(function (o) {
        var keys = Object.keys(o).sort(),
            key = keys.join('|'),
            value = keys.map(function (k) { return o[k]; }).join('|');

        return hash[key] && hash[key][value] && hash[key][value]--;
    });
}

console.log(compareArrays([{ foo: 'foo', bar: 'bar' }, { baz: 'baz' }], [{ baz: 'baz' }, { foo: 'foo', bar: 'bar' }]));
console.log(compareArrays([{ foo: 'foo', bar: 'bar' }, { baz: 'baz' }, { baz: 'baz' }], [{ baz: 'baz' }, { foo: 'foo', bar: 'bar' }]));
console.log(compareArrays([{ foo: 'foo', bar: 'bar' }, { baz: 'baz' }, { foo: 'baz' }], [{ baz: 'baz' }, { foo: 'foo', bar: 'bar' }]));
console.log(compareArrays([{ foo: 'foo', bar: 'bar' }, { baz: 'baz' }, { foo: 'baz' }], [{ baz: 'baz' }, { foo: 'foo', bar: 'bar' }, { foo: 42 }]));


然而,它无法处理键或值包含 | 的对象。也无法处理根本不是字符串的值。我建议对排序后的键和值数组使用 JSON.stringify() - Bergi
还可以通过将“key”和“value”连接起来而不是嵌套查找表来简化。 - Bergi

0

你可以尝试以下方法:

  • 将每个数组中的多个对象减少为一个
  • 对键进行排序并构建2D数组或构建新对象
  • 比较两个新构建的数据结构(2D数组/对象)

这可以推广到任意数量的数组。

const arr1 = [{ foo: 'foo', bar: 'bar' }, { baz: 'baz' }]; 
const arr2 = [{ baz: 'baz' }, { foo: 'foo', bar: 'bar' }];

// Method that sorts the object keys and builds a new object
// sortObj = (obj) =>
//   Object.keys(obj).sort().reduce((a, b) => {a[b] = obj[b]; return a}, {})
  
// Method that sorts keys and builds a 2D array
sortObj = (obj) =>
    Object.keys(obj).sort().map((key) => [key, obj[key]])

compareObj = (arr1, arr2) => {
  if(arr1.length !== arr2.length)
     return false;
 
  // 1st array reduce
  const reduceArr1 = arr1.reduce((a, b) => ({...a, ...b}), {});
  
  // 2nd array reduce
  const reduceArr2 = arr2.reduce((a, b) => ({...a, ...b}), {});
  
  // Comparing the sortedObjects
  return JSON.stringify(sortObj(reduceArr1)) === JSON.stringify(sortObj(reduceArr2))
}

console.log(compareObj(arr1, arr2))


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