سؤال

أريد مقارنة صفيفتين من الكائنات في كود JavaScript.تحتوي الكائنات على 8 خصائص إجمالية، ولكن لن يكون لكل كائن قيمة لكل منها، ولن تكون المصفوفات أبدًا أكبر من 8 عناصر لكل منها، لذلك ربما تكون طريقة القوة الغاشمة لاجتياز كل منها ثم النظر إلى قيم 8 خصائص هي أسهل طريقة لفعل ما أريد القيام به، ولكن قبل التنفيذ، أردت معرفة ما إذا كان لدى أي شخص حل أكثر أناقة.أي أفكار؟

هل كانت مفيدة؟

المحلول

يحرر:لا يمكنك زيادة تحميل المشغلين في التطبيقات الحالية الشائعة المستندة إلى المستعرض لمترجمي JavaScript.

للإجابة على السؤال الأصلي، إحدى الطرق التي يمكنك من خلالها القيام بذلك، وتذكر أن هذا ببساطة نوع من الاختراق قم بإجراء تسلسل للصفيفين إلى JSON ثم قارن بين سلسلتي JSON.سيخبرك ذلك ببساطة ما إذا كانت المصفوفات مختلفة، ومن الواضح أنه يمكنك القيام بذلك كل للكائنات الموجودة داخل المصفوفات أيضًا لمعرفة أي منها كان مختلفًا.

هناك خيار آخر وهو استخدام مكتبة تحتوي على بعض المرافق الرائعة لمقارنة الكائنات - وأنا أستخدمها وأوصي بها MochiKit.


يحرر: الجواب الذي قدمه كامينز يستحق الاهتمام أيضًا، نظرًا لأن وظيفة واحدة لمقارنة كائنين معينين ستكون أصغر بكثير من أي مكتبة للقيام بما أقترحه (على الرغم من أن اقتراحي سيعمل بالتأكيد بشكل جيد بما فيه الكفاية).

فيما يلي تطبيق ساذج قد يكون كافيًا بالنسبة لك - انتبه إلى وجود مشكلات محتملة في هذا التنفيذ:

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

الافتراض هو أن كلا الكائنين لهما نفس قائمة الخصائص بالضبط.

وربما يكون من الواضح أنني، في السراء والضراء، أنتمي إلى معسكر نقطة العودة الوحيدة.:)

نصائح أخرى

أعلم أن هذا سؤال قديم وأن الإجابات المقدمة تعمل بشكل جيد ...ولكن هذا أقصر قليلاً ولا يتطلب أي مكتبات إضافية (على سبيل المثال.جسون ):

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

بصراحة، مع وجود 8 كائنات كحد أقصى و8 خصائص كحد أقصى لكل كائن، فإن أفضل رهان لك هو اجتياز كل كائن وإجراء المقارنات مباشرة.سيكون الأمر سريعًا وسيكون سهلاً.

إذا كنت ستستخدم هذه الأنواع من المقارنات كثيرًا، فأنا أتفق مع جيسون بشأن تسلسل JSON... ولكن بخلاف ذلك ليست هناك حاجة لإبطاء تطبيقك باستخدام مكتبة جديدة أو رمز تسلسل JSON.

لقد عملت قليلاً على خوارزمية بسيطة لمقارنة محتويات كائنين وإرجاع قائمة واضحة بالاختلافات.اعتقدت أنني سوف أشارك.يستعير بعض الأفكار لـ jQuery، وهي map تنفيذ الوظيفة والتحقق من نوع الكائن والصفيف.

تقوم بإرجاع قائمة "الكائنات المختلفة"، وهي عبارة عن صفائف تحتوي على معلومات الفرق.انه بسيط جدا.

ها هو:

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

حاولت 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

نظرًا لأن التسلسل لا يعمل بشكل عام (فقط عندما يتطابق ترتيب الخصائص: 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

إذا كنت بحاجة إلى مقارنة عميقة، يمكنك استدعاء الدالة بشكل متكرر:

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

فمن السهل استخدام هذه الوظيفة لمقارنة الكائنات في المصفوفات:

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

من فضلك جرب هذا:

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

ها هي محاولتي باستخدام وحدة تأكيد العقدة + حزمة npm تجزئة الكائن.

أفترض أنك ترغب في التحقق مما إذا كان هناك صفيفان يحتويان على نفس الكائنات، حتى لو تم ترتيب هذه الكائنات بشكل مختلف بين الصفيفين.

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

ال objectsAreSame الوظيفة المذكورة في إجابة @JasonBunting تعمل بشكل جيد بالنسبة لي.ومع ذلك، هناك مشكلة صغيرة:لو x[propertyName] و y[propertyName] هي كائنات (typeof x[propertyName] == 'object')، ستحتاج إلى استدعاء الدالة بشكل متكرر لمقارنتها.

استخدام _.some من لوداش: https://lodash.com/docs/4.17.11#some

const array1AndArray2NotEqual = 
          _.some(array1, (a1, idx) => a1.key1 !== array2[idx].key1 
                                     || a1.key2 !== array2[idx].key2 
                                     || a1.key3 !== array2[idx].key3);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top