比较JavaScript中的对象数组。

时间:2022-10-02 12:16:56

I want to compare 2 arrays of objects in JavaScript code. The objects have 8 total properties, but each object will not have a value for each, and the arrays are never going to be any larger than 8 items each, so maybe the brute force method of traversing each and then looking at the values of the 8 properties is the easiest way to do what I want to do, but before implementing, I wanted to see if anyone had a more elegant solution. Any thoughts?

我想比较JavaScript代码中的两个对象数组。对象总共8个属性,但每个,每个对象不会有值,数组是永远不会是任何超过8项,所以可能的蛮力方法遍历每一个,然后看着8属性的值是最简单的方法去做我想做的事,但在实现之前,我想看看是否有人更优雅的解决方案。任何想法吗?

7 个解决方案

#1


34  

EDIT: You cannot overload operators in current, common browser-based implementations of JavaScript interpreters.

编辑:不能在当前基于浏览器的JavaScript解释器实现中重载操作符。

To answer the original question, one way you could do this, and mind you, this is a bit of a hack, simply serialize the two arrays to JSON and then compare the two JSON strings. That would simply tell you if the arrays are different, obviously you could do this to each of the objects within the arrays as well to see which ones were different.

要回答最初的问题,有一种方法可以做到这一点,请注意,这有点麻烦,只需将两个数组序列化为JSON,然后比较两个JSON字符串。这只会告诉你数组是否不同,显然你可以对数组中的每个对象都这样做,看看哪些是不同的。

Another option is to use a library which has some nice facilities for comparing objects - I use and recommend MochiKit.

另一种选择是使用一个库来比较对象——我使用并推荐MochiKit。


EDIT: The answer kamens gave deserves consideration as well, since a single function to compare two given objects would be much smaller than any library to do what I suggest (although my suggestion would certainly work well enough).

编辑:kamens给出的答案也值得考虑,因为比较两个给定对象的单个函数要比我建议的任何库都要小得多(尽管我的建议肯定会很好)。

Here is a naïve implemenation that may do just enough for you - be aware that there are potential problems with this implementation:

这里有一个简单的实现,可能对您已经足够了——请注意这个实现存在潜在的问题:

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

The assumption is that both objects have the same exact list of properties.

假设两个对象都有相同的属性列表。

Oh, and it is probably obvious that, for better or worse, I belong to the only-one-return-point camp. :)

哦,也许很明显,不管怎样,我属于唯一的一个返点阵营。:)

#2


13  

I know this is an old question and the answers provided work fine ... but this is a bit shorter and doesn't require any additional libraries ( i.e. JSON ):

我知道这是一个老问题,答案很好……但是这要短一些,并且不需要任何其他库(例如JSON):

function arraysAreEqual(ary1,ary2){
  return (ary1.join('') == ary2.join(''));
}

#3


10  

Honestly, with 8 objects max and 8 properties max per object, your best bet is to just traverse each object and make the comparisons directly. It'll be fast and it'll be easy.

老实说,对于每个对象最多有8个对象和8个属性,最好的方法是遍历每个对象并直接进行比较。它会很快,也会很容易。

If you're going to be using these types of comparisons often, then I agree with Jason about JSON serialization...but otherwise there's no need to slow down your app with a new library or JSON serialization code.

如果您经常使用这些类型的比较,那么我同意Jason关于JSON序列化的看法……但是,没有必要使用新的库或JSON序列化代码来降低应用程序的速度。

#4


7  

I have worked a bit on a simple algorithm to compare contents of two objects and return an intelligible list of difference. Thought I would share. It borrows some ideas for jQuery, namely the map function implementation and the object and array type checking.

我在一个简单的算法上做了一些工作来比较两个对象的内容并返回一个可理解的差异列表。想我应该分享。它借鉴了jQuery的一些思想,即映射函数实现和对象和数组类型检查。

It returns a list of "diff objects", which are arrays with the diff info. It's very simple.

它返回一个“diff对象”列表,这些对象是带有diff信息的数组。很简单。

Here it is:

这里是:

// 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;
}

#5


0  

Please try this one:

请试试这个:

function used_to_compare_two_arrays(a, b)
{
  // This block will make the array of indexed that array b contains a elements
  var c = a.filter(function(value, index, obj) {
    return b.indexOf(value) > -1;
  });

  // This is used for making comparison that both have same length if no condition go wrong 
  if (c.length !== a.length) {
    return 0;
  } else{
    return 1;
  }
}

#6


0  

Here is my attempt, using Node's assert module + npm package object-hash.

下面是我的尝试,使用Node的assert模块+ npm包对象哈希。

I suppose that you would like to check if two arrays contain the same objects, even if those objects are ordered differently between the two arrays.

我假设您希望检查两个数组是否包含相同的对象,即使这些对象在两个数组之间的顺序不同。

var assert = require('assert');
var hash = require('object-hash');

var obj1 = {a: 1, b: 2, c: 333},
    obj2 = {b: 2, a: 1, c: 444},
    obj3 = {b: "AAA", c: 555},
    obj4 = {c: 555, b: "AAA"};

var array1 = [obj1, obj2, obj3, obj4];
var array2 = [obj3, obj2, obj4, obj1]; // [obj3, obj3, obj2, obj1] should work as well

// calling assert.deepEquals(array1, array2) at this point FAILS (throws an AssertionError)
// even if array1 and array2 contain the same objects in different order,
// because array1[0].c !== array2[0].c

// sort objects in arrays by their hashes, so that if the arrays are identical,
// their objects can be compared in the same order, one by one
var array1 = sortArrayOnHash(array1);
var array2 = sortArrayOnHash(array2);

// then, this should output "PASS"
try {
    assert.deepEqual(array1, array2);
    console.log("PASS");
} catch (e) {
    console.log("FAIL");
    console.log(e);
}

// You could define as well something like Array.prototype.sortOnHash()...
function sortArrayOnHash(array) {
    return array.sort(function(a, b) {
        return hash(a) > hash(b);
    });
}

#7


0  

The objectsAreSame function mentioned in @JasonBunting's answer works fine for me. However, there's a little problem: If x[propertyName] and y[propertyName] are objects (typeof x[propertyName] == 'object'), you'll need to call the function recursively in order to compare them.

@JasonBunting的回答中提到的objectsAreSame函数对我来说没问题。但是,有一个小问题:如果x[propertyName]和y[propertyName]是对象(typeof x[propertyName] = 'object'),那么需要递归地调用函数来比较它们。

#1


34  

EDIT: You cannot overload operators in current, common browser-based implementations of JavaScript interpreters.

编辑:不能在当前基于浏览器的JavaScript解释器实现中重载操作符。

To answer the original question, one way you could do this, and mind you, this is a bit of a hack, simply serialize the two arrays to JSON and then compare the two JSON strings. That would simply tell you if the arrays are different, obviously you could do this to each of the objects within the arrays as well to see which ones were different.

要回答最初的问题,有一种方法可以做到这一点,请注意,这有点麻烦,只需将两个数组序列化为JSON,然后比较两个JSON字符串。这只会告诉你数组是否不同,显然你可以对数组中的每个对象都这样做,看看哪些是不同的。

Another option is to use a library which has some nice facilities for comparing objects - I use and recommend MochiKit.

另一种选择是使用一个库来比较对象——我使用并推荐MochiKit。


EDIT: The answer kamens gave deserves consideration as well, since a single function to compare two given objects would be much smaller than any library to do what I suggest (although my suggestion would certainly work well enough).

编辑:kamens给出的答案也值得考虑,因为比较两个给定对象的单个函数要比我建议的任何库都要小得多(尽管我的建议肯定会很好)。

Here is a naïve implemenation that may do just enough for you - be aware that there are potential problems with this implementation:

这里有一个简单的实现,可能对您已经足够了——请注意这个实现存在潜在的问题:

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

The assumption is that both objects have the same exact list of properties.

假设两个对象都有相同的属性列表。

Oh, and it is probably obvious that, for better or worse, I belong to the only-one-return-point camp. :)

哦,也许很明显,不管怎样,我属于唯一的一个返点阵营。:)

#2


13  

I know this is an old question and the answers provided work fine ... but this is a bit shorter and doesn't require any additional libraries ( i.e. JSON ):

我知道这是一个老问题,答案很好……但是这要短一些,并且不需要任何其他库(例如JSON):

function arraysAreEqual(ary1,ary2){
  return (ary1.join('') == ary2.join(''));
}

#3


10  

Honestly, with 8 objects max and 8 properties max per object, your best bet is to just traverse each object and make the comparisons directly. It'll be fast and it'll be easy.

老实说,对于每个对象最多有8个对象和8个属性,最好的方法是遍历每个对象并直接进行比较。它会很快,也会很容易。

If you're going to be using these types of comparisons often, then I agree with Jason about JSON serialization...but otherwise there's no need to slow down your app with a new library or JSON serialization code.

如果您经常使用这些类型的比较,那么我同意Jason关于JSON序列化的看法……但是,没有必要使用新的库或JSON序列化代码来降低应用程序的速度。

#4


7  

I have worked a bit on a simple algorithm to compare contents of two objects and return an intelligible list of difference. Thought I would share. It borrows some ideas for jQuery, namely the map function implementation and the object and array type checking.

我在一个简单的算法上做了一些工作来比较两个对象的内容并返回一个可理解的差异列表。想我应该分享。它借鉴了jQuery的一些思想,即映射函数实现和对象和数组类型检查。

It returns a list of "diff objects", which are arrays with the diff info. It's very simple.

它返回一个“diff对象”列表,这些对象是带有diff信息的数组。很简单。

Here it is:

这里是:

// 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;
}

#5


0  

Please try this one:

请试试这个:

function used_to_compare_two_arrays(a, b)
{
  // This block will make the array of indexed that array b contains a elements
  var c = a.filter(function(value, index, obj) {
    return b.indexOf(value) > -1;
  });

  // This is used for making comparison that both have same length if no condition go wrong 
  if (c.length !== a.length) {
    return 0;
  } else{
    return 1;
  }
}

#6


0  

Here is my attempt, using Node's assert module + npm package object-hash.

下面是我的尝试,使用Node的assert模块+ npm包对象哈希。

I suppose that you would like to check if two arrays contain the same objects, even if those objects are ordered differently between the two arrays.

我假设您希望检查两个数组是否包含相同的对象,即使这些对象在两个数组之间的顺序不同。

var assert = require('assert');
var hash = require('object-hash');

var obj1 = {a: 1, b: 2, c: 333},
    obj2 = {b: 2, a: 1, c: 444},
    obj3 = {b: "AAA", c: 555},
    obj4 = {c: 555, b: "AAA"};

var array1 = [obj1, obj2, obj3, obj4];
var array2 = [obj3, obj2, obj4, obj1]; // [obj3, obj3, obj2, obj1] should work as well

// calling assert.deepEquals(array1, array2) at this point FAILS (throws an AssertionError)
// even if array1 and array2 contain the same objects in different order,
// because array1[0].c !== array2[0].c

// sort objects in arrays by their hashes, so that if the arrays are identical,
// their objects can be compared in the same order, one by one
var array1 = sortArrayOnHash(array1);
var array2 = sortArrayOnHash(array2);

// then, this should output "PASS"
try {
    assert.deepEqual(array1, array2);
    console.log("PASS");
} catch (e) {
    console.log("FAIL");
    console.log(e);
}

// You could define as well something like Array.prototype.sortOnHash()...
function sortArrayOnHash(array) {
    return array.sort(function(a, b) {
        return hash(a) > hash(b);
    });
}

#7


0  

The objectsAreSame function mentioned in @JasonBunting's answer works fine for me. However, there's a little problem: If x[propertyName] and y[propertyName] are objects (typeof x[propertyName] == 'object'), you'll need to call the function recursively in order to compare them.

@JasonBunting的回答中提到的objectsAreSame函数对我来说没问题。但是,有一个小问题:如果x[propertyName]和y[propertyName]是对象(typeof x[propertyName] = 'object'),那么需要递归地调用函数来比较它们。