【问题标题】:Compare unsorted arrays of objects in Javascript比较Javascript中未排序的对象数组
【发布时间】:2018-05-15 07:32:37
【问题描述】:

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

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

我知道已经有很多关于比较对象数组的答案,但我并没有真正找到比较未排序版本数组的明确答案。

【问题讨论】:

  • function compareObjs() { return true } 会这样做。 为什么你期望它返回真,什么时候不应该?
  • 我希望这是真的,因为两个数组的长度相同并且它们包含相同的对象(相同的键和值)。在这种情况下,对象引用无关紧要。
  • 这里的几个问题都问同样的问题。查看:stackoverflow.com/questions/9191791/…stackoverflow.com/questions/201183/…
  • @Shota 你能把它们排序吗?
  • 我已经阅读了那个答案,但是 JSON.stringify 不起作用,因为数组没有排序,我不能使用 lodash,我必须在 Vanilla JS 中这样做

标签: javascript arrays


【解决方案1】:

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

如果您不介意 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))

【讨论】:

    【解决方案2】:

    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'
      }]
    ))

    【讨论】:

    • 不幸的是,这不起作用:您没有保留每个对象的结构。看看这里,你的代码有两个明显不同的数组:jsfiddle.net/1myf4cvk
    • 是的,我认为他有不同的用例。我现在看到了。
    • 您需要在giveMeSanitisedObject 中使用reduce 而不是forEach。而且您需要使用[property] 而不是.property
    【解决方案3】:

    一种基本的方法是遍历一个数组的所有对象,看看是否可以在另一个数组中找到相似的对象。

    这是一个例子:

    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);

    【讨论】:

      【解决方案4】:

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

      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()
      • 您也可以通过连接keyvalue 而不是嵌套查找表来简化。
      【解决方案5】:

      你可以试试下面的方法

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

      这可以外推到任意数量的数组

      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))

      【讨论】:

        【解决方案6】:

        这里有另一种可能性:

        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() 来改进原始类型
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多