比较JavaScript中的对象数组

Ada*_*amB 53 javascript arrays comparison

我想比较JavaScript代码中的2个对象数组.这些对象有8个属性,但是每个对象都没有每个对象的值,并且数组永远不会超过8个项目,所以也许是通过遍历每个对象然后查看值的强力方法. 8个属性是我想做的最简单的方法,但在实现之前,我想看看是否有人有更优雅的解决方案.有什么想法吗?

Jas*_*ing 45

编辑:您不能在当前常见的基于浏览器的JavaScript解释器实现中重载运算符.

要回答原始问题,一种方法可以做到这一点,并且请注意,这有点像黑客,只需将两个数组序列化为JSON,然后比较两个JSON字符串.这只会告诉你数组是否不同,显然你可以对数组中的每个对象执行此操作,以查看哪些不同.

另一个选择是使用一个库,它有一些很好的设施来比较对象 - 我使用和推荐MochiKit.


编辑: 答案kamens也值得考虑,因为比较两个给定对象的单个函数将比任何库小得多做我建议(虽然我的建议肯定会运作良好).

这是一个天真的实现,可能对您足够 - 请注意这个实现存在潜在的问题:

function objectsAreSame(x, y) {
   var objectsAreSame = true;
   for(var propertyName in x) {
      if(x[propertyName] !== y[propertyName]) {
         objectsAreSame = false;
         break;
      }
   }
   return objectsAreSame;
}
Run Code Online (Sandbox Code Playgroud)

假设两个对象具有完全相同的属性列表.

哦,很明显,无论好坏,我都属于唯一一个回归点阵营.:)

  • 关于JSON序列化建议的一个警告是,如果您正在比较对象(而不是数组)并且不关心顺序(例如命名键,而不是数值数组),那么JSON序列化将不起作用. (4认同)
  • 忘记对象数组和对象数组,无论这意味着什么。想想`{a: 1, b: 1}`和`{b: 1, a: 1}`。我们不关心对象的顺序,但这些字符串显然不同。 (3认同)
  • 只是指出限制:在比较包含对象的对象时,它看起来会失败.(正如你所提到的,当两个对象没有"同一个完全相同的属性列表"时,它会失败,因为`y`被允许是一个超级的`x`集. (2认同)

小智 17

我知道这是一个老问题,并且所提供的答案工作得很好......但这有点短,不需要任何额外的库(即JSON):

function arraysAreEqual(ary1,ary2){
  return (ary1.join('') == ary2.join(''));
}
Run Code Online (Sandbox Code Playgroud)

  • OP希望加入对象数组.这仅适用于标量数组. (11认同)
  • 它也很脆弱.如果:`a = ["1,2"],b = ["1","2"]`那么两个不同数组上的`join()`将导致''1,2' (8认同)
  • 你对这个特定的例子是正确的,但它仍然很脆弱.`a = ["12"],b = ["1","2"]`导致`"12"=="12"`我不认为任何分隔符可以拯救你,因为它可能在obj本身.长度检查也不能修复它,因为`a = ["12","3"],b = ["1","23"]` (7认同)
  • 一个稍微强大的实现:`return ary1.join(',')=== ary2.join(',');` (4认同)

kam*_*ens 15

老实说,每个对象最多8个对象,最多8个属性,最好的办法就是遍历每个对象并直接进行比较.它会很快,而且很容易.

如果您经常使用这些类型的比较,那么我同意Jason关于JSON序列化......但是否则不需要使用新库或JSON序列化代码来减慢您的应用程序速度.

  • "......我同意Jason关于JSON ......"+1就是为了这个!;-) (31认同)

Yuv*_*val 13

我已经研究了一个简单的算法来比较两个对象的内容并返回一个可理解的差异列表.以为我会分享.它借鉴了jQuery的一些想法,即map函数实现以及对象和数组类型检查.

它返回一个"diff objects"列表,它是带有diff信息的数组.这很简单.

这里是:

// compare contents of two objects and return a list of differences
// returns an array where each element is also an array in the form:
// [accessor, diffType, leftValue, rightValue ]
//
// diffType is one of the following:
//   value: when primitive values at that index are different
//   undefined: when values in that index exist in one object but don't in 
//              another; one of the values is always undefined
//   null: when a value in that index is null or undefined; values are
//         expressed as boolean values, indicated wheter they were nulls
//   type: when values in that index are of different types; values are 
//         expressed as types
//   length: when arrays in that index are of different length; values are
//           the lengths of the arrays
//

function DiffObjects(o1, o2) {
    // choose a map() impl.
    // you may use $.map from jQuery if you wish
    var map = Array.prototype.map?
        function(a) { return Array.prototype.map.apply(a, Array.prototype.slice.call(arguments, 1)); } :
        function(a, f) { 
            var ret = new Array(a.length), value;
            for ( var i = 0, length = a.length; i < length; i++ ) 
                ret[i] = f(a[i], i);
            return ret.concat();
        };

    // shorthand for push impl.
    var push = Array.prototype.push;

    // check for null/undefined values
    if ((o1 == null) || (o2 == null)) {
        if (o1 != o2)
            return [["", "null", o1!=null, o2!=null]];

        return undefined; // both null
    }
    // compare types
    if ((o1.constructor != o2.constructor) ||
        (typeof o1 != typeof o2)) {
        return [["", "type", Object.prototype.toString.call(o1), Object.prototype.toString.call(o2) ]]; // different type

    }

    // compare arrays
    if (Object.prototype.toString.call(o1) == "[object Array]") {
        if (o1.length != o2.length) { 
            return [["", "length", o1.length, o2.length]]; // different length
        }
        var diff =[];
        for (var i=0; i<o1.length; i++) {
            // per element nested diff
            var innerDiff = DiffObjects(o1[i], o2[i]);
            if (innerDiff) { // o1[i] != o2[i]
                // merge diff array into parent's while including parent object name ([i])
                push.apply(diff, map(innerDiff, function(o, j) { o[0]="[" + i + "]" + o[0]; return o; }));
            }
        }
        // if any differences were found, return them
        if (diff.length)
            return diff;
        // return nothing if arrays equal
        return undefined;
    }

    // compare object trees
    if (Object.prototype.toString.call(o1) == "[object Object]") {
        var diff =[];
        // check all props in o1
        for (var prop in o1) {
            // the double check in o1 is because in V8 objects remember keys set to undefined 
            if ((typeof o2[prop] == "undefined") && (typeof o1[prop] != "undefined")) {
                // prop exists in o1 but not in o2
                diff.push(["[" + prop + "]", "undefined", o1[prop], undefined]); // prop exists in o1 but not in o2

            }
            else {
                // per element nested diff
                var innerDiff = DiffObjects(o1[prop], o2[prop]);
                if (innerDiff) { // o1[prop] != o2[prop]
                    // merge diff array into parent's while including parent object name ([prop])
                    push.apply(diff, map(innerDiff, function(o, j) { o[0]="[" + prop + "]" + o[0]; return o; }));
                }

            }
        }
        for (var prop in o2) {
            // the double check in o2 is because in V8 objects remember keys set to undefined 
            if ((typeof o1[prop] == "undefined") && (typeof o2[prop] != "undefined")) {
                // prop exists in o2 but not in o1
                diff.push(["[" + prop + "]", "undefined", undefined, o2[prop]]); // prop exists in o2 but not in o1

            }
        }
        // if any differences were found, return them
        if (diff.length)
            return diff;
        // return nothing if objects equal
        return undefined;
    }
    // if same type and not null or objects or arrays
    // perform primitive value comparison
    if (o1 != o2)
        return [["", "value", o1, o2]];

    // return nothing if values are equal
    return undefined;
}
Run Code Online (Sandbox Code Playgroud)


小智 9

我试过JSON.stringify()并为我工作.

let array1 = [1,2,{value:'alpha'}] , array2 = [{value:'alpha'},'music',3,4];

JSON.stringify(array1) // "[1,2,{"value":"alpha"}]"

JSON.stringify(array2) // "[{"value":"alpha"},"music",3,4]"

JSON.stringify(array1) === JSON.stringify(array2); // false
Run Code Online (Sandbox Code Playgroud)

  • 这里要注意-如果对象属性混乱,则此方法将无效 (8认同)
  • @Ehsansarshar,这不起作用......你需要对所有对象属性和数组进行排序...... (3认同)

ttu*_*lka 9

由于序列化通常不起作用(仅当属性顺序匹配时:),因此JSON.stringify({a:1,b:2}) !== JSON.stringify({b:2,a:1})您必须检查属性计数并比较每个属性:

const objectsEqual = (o1, o2) =>
    Object.keys(o1).length === Object.keys(o2).length 
        && Object.keys(o1).every(p => o1[p] === o2[p]);

const obj1 = { name: 'John', age: 33};
const obj2 = { age: 33, name: 'John' };
const obj3 = { name: 'John', age: 45 };
        
console.log(objectsEqual(obj1, obj2)); // true
console.log(objectsEqual(obj1, obj3)); // false
Run Code Online (Sandbox Code Playgroud)

如果需要深入比较,可以递归调用该函数:

const obj1 = { name: 'John', age: 33, info: { married: true, hobbies: ['sport', 'art'] } };
const obj2 = { age: 33, name: 'John', info: { hobbies: ['sport', 'art'], married: true } };
const obj3 = { name: 'John', age: 33 };

const objectsEqual = (o1, o2) => 
    typeof o1 === 'object' && Object.keys(o1).length > 0 
        ? Object.keys(o1).length === Object.keys(o2).length 
            && Object.keys(o1).every(p => objectsEqual(o1[p], o2[p]))
        : o1 === o2;
        
console.log(objectsEqual(obj1, obj2)); // true
console.log(objectsEqual(obj1, obj3)); // false
Run Code Online (Sandbox Code Playgroud)

然后,使用此函数比较数组中的对象很容易:

const arr1 = [obj1, obj1];
const arr2 = [obj1, obj2];
const arr3 = [obj1, obj3];

const arraysEqual = (a1, a2) => 
   a1.length === a2.length && a1.every((o, idx) => objectsEqual(o, a2[idx]));

console.log(arraysEqual(arr1, arr2)); // true
console.log(arraysEqual(arr1, arr3)); // false
Run Code Online (Sandbox Code Playgroud)

  • 最佳答案。简洁又完美。应该在上面。 (3认同)
  • 不考虑顺序。不适用于以下情况 const arr1 = [obj1, obj2]; const arr2 = [obj2, obj1]; (2认同)
  • 最佳答案,为我节省了大量时间。谢谢你! (2认同)

Wol*_*ram 7

对于函数需要等于空数组的情况有一个优化的代码(在这种情况下返回 false)

const objectsEqual = (o1, o2) => {
    if (o2 === null && o1 !== null) return false;
    return o1 !== null && typeof o1 === 'object' && Object.keys(o1).length > 0 ?
        Object.keys(o1).length === Object.keys(o2).length && 
        Object.keys(o1).every(p => objectsEqual(o1[p], o2[p]))
        : (o1 !== null && Array.isArray(o1) && Array.isArray(o2) && !o1.length && 
        !o2.length) ? true : o1 === o2;
}
Run Code Online (Sandbox Code Playgroud)