JavaScript コードでオブジェクトの 2 つの配列を比較したいと考えています。オブジェクトには合計 8 つのプロパティがありますが、各オブジェクトにはそれぞれの値がなく、配列がそれぞれ 8 項目よりも大きくなることはありません。 8 つのプロパティは、私がやりたいことを行うための最も簡単な方法ですが、実装する前に、誰かがより洗練されたソリューションを持っているかどうかを確認したかったのです。何かご意見は?
16 に答える
通常、シリアル化は機能しないため (プロパティの順序が一致する場合のみ: 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
編集: JavaScript インタープリターの現在の一般的なブラウザーベースの実装では、演算子をオーバーロードできません。
元の質問に答えるには、これを行う 1 つの方法であり、注意してください。これはちょっとしたハックです。単純に 2 つの配列を JSON にシリアル化し、2つの JSON 文字列を比較します。これは単に配列が異なるかどうかを示します。明らかに、配列内の各オブジェクトに対してもこれを実行して、どのオブジェクトが異なるかを確認できます。
別のオプションは、オブジェクトを比較するための優れた機能を備えたライブラリを使用することです - 私はMochiKitを使用し、お勧めします。
編集: 2 つの特定のオブジェクトを比較する単一の関数は、私が提案することを実行するライブラリよりもはるかに小さいため、 kamens の回答も考慮に値します (ただし、私の提案は十分に機能します)。
これはあなたにとって十分な単純な実装です - この実装には潜在的な問題があることに注意してください:
function objectsAreSame(x, y) {
var objectsAreSame = true;
for(var propertyName in x) {
if(x[propertyName] !== y[propertyName]) {
objectsAreSame = false;
break;
}
}
return objectsAreSame;
}
両方のオブジェクトがまったく同じプロパティのリストを持っていることを前提としています。
ああ、そして、良くも悪くも、私が唯一の帰還点キャンプに属していることはおそらく明らかです. :)
正直なところ、オブジェクトごとに最大8つのオブジェクトと最大8つのプロパティがあるため、最善の策は、各オブジェクトをトラバースして直接比較することです。それは速くて簡単でしょう。
これらのタイプの比較を頻繁に使用する場合は、JSONシリアル化についてJasonに同意します...ただし、それ以外の場合は、新しいライブラリまたはJSONシリアル化コードでアプリの速度を落とす必要はありません。
これは古い質問であり、提供された回答は正常に機能することを私は知っています...しかし、これは少し短く、追加のライブラリ(つまりJSON)を必要としません:
function arraysAreEqual(ary1,ary2){
return (ary1.join('') == ary2.join(''));
}
2 つのオブジェクトの内容を比較し、わかりやすい違いのリストを返す単純なアルゴリズムに少し取り組みました。私が共有すると思った。map
関数の実装、オブジェクトと配列の型チェックなど、jQuery のアイデアを取り入れています。
差分情報を含む配列である「差分オブジェクト」のリストを返します。とても簡単です。
ここにあります:
// 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
これをお試し下さい:
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;
}
}
objectsAreSame
@JasonBuntingの回答に記載されている機能は、私にとってはうまく機能します。ただし、少し問題があります。x[propertyName]
とy[propertyName]
がオブジェクト ( typeof x[propertyName] == 'object'
) の場合、それらを比較するために関数を再帰的に呼び出す必要があります。
パフォーマンスについては不明です...大きなオブジェクトでテストする必要があります..しかし、これは私にとってはうまく機能します..他のソリューションと比較した利点は、オブジェクト/配列が同じ順序である必要がないことです....
実際には、最初の配列の最初のオブジェクトを取得し、すべてのオブジェクトについて2番目の配列をスキャンします..一致する場合は、別の配列に進みます
最適化の方法は絶対にありますが、それは機能しています:)
@ttulka さんへthx私は彼の作品に触発されました ... 少しだけ作業しました
const objectsEqual = (o1, o2) => {
let match = false
if(typeof o1 === 'object' && Object.keys(o1).length > 0) {
match = (Object.keys(o1).length === Object.keys(o2).length && Object.keys(o1).every(p => objectsEqual(o1[p], o2[p])))
}else {
match = (o1 === o2)
}
return match
}
const arraysEqual = (a1, a2) => {
let finalMatch = []
let itemFound = []
if(a1.length === a2.length) {
finalMatch = []
a1.forEach( i1 => {
itemFound = []
a2.forEach( i2 => {
itemFound.push(objectsEqual(i1, i2))
})
finalMatch.push(itemFound.some( i => i === true))
})
}
return finalMatch.every(i => i === true)
}
const ar1 = [
{ id: 1, name: "Johnny", data: { body: "Some text"}},
{ id: 2, name: "Jimmy"}
]
const ar2 = [
{name: "Jimmy", id: 2},
{name: "Johnny", data: { body: "Some text"}, id: 1}
]
console.log("Match:",arraysEqual(ar1, ar2))
jsfiddle: https://jsfiddle.net/x1pubs6q/
または単にlodashを使用してください:))))
const _ = require('lodash')
const isArrayEqual = (x, y) => {
return _.isEmpty(_.xorWith(x, y, _.isEqual));
};
私の解決策があります。オブジェクトと配列も持つ配列を比較します。要素は任意の位置にとどまることができます。例:
const array1 = [{a: 1}, {b: 2}, { c: 0, d: { e: 1, f: 2, } }, [1,2,3,54]];
const array2 = [{a: 1}, {b: 2}, { c: 0, d: { e: 1, f: 2, } }, [1,2,3,54]];
const arraysCompare = (a1, a2) => {
if (a1.length !== a2.length) return false;
const objectIteration = (object) => {
const result = [];
const objectReduce = (obj) => {
for (let i in obj) {
if (typeof obj[i] !== 'object') {
result.push(`${i}${obj[i]}`);
} else {
objectReduce(obj[i]);
}
}
};
objectReduce(object);
return result;
};
const reduceArray1 = a1.map(item => {
if (typeof item !== 'object') return item;
return objectIteration(item).join('');
});
const reduceArray2 = a2.map(item => {
if (typeof item !== 'object') return item;
return objectIteration(item).join('');
});
const compare = reduceArray1.map(item => reduceArray2.includes(item));
return compare.reduce((acc, item) => acc + Number(item)) === a1.length;
};
console.log(arraysCompare(array1, array2));