简体   繁体   English

对于一组 JSON 符合 object 文字,如何比较这些项目的相等性?

[英]For an array of JSON conform object literals, how does one compare the equality of such items?

How to check if array contains different values with React.js and typescript?如何使用 React.js 和 typescript 检查数组是否包含不同的值?

Example:例子:

[{
  name: 'John',
  value: 1,
}, {
  name: 'John',
  value: 1,
}, {
  name: 'Carla',
  value: 15,
}]

I want to return false if all objects in array are same, and true if there is at least one different object.如果数组中的所有对象都相同,我想返回 false,如果至少有一个不同的 object,我想返回 true。

You can't use a direct equality comparison since objects will never return equal.您不能使用直接相等比较,因为对象永远不会返回相等。

Ie {} != {} , and {name: 'John', value: 1} != {name: 'John', value: 1} .{} != {}{name: 'John', value: 1} != {name: 'John', value: 1}

So firstly you have to decide what you're going to define as 'equal' for these objects.因此,首先您必须决定要为这些对象定义什么“相等”。

Let's say for the sake of this that you use just the name field as the test for equality.为此,假设您仅使用name字段作为相等性测试。 So if two objects in the array have the same name field, then you'll call them equal.因此,如果数组中的两个对象具有相同的name字段,那么您将称它们为相等。 Then you'd define the function:然后定义 function:

type NameValue = {name: string, value: string}

const areEqual = (obj1: NameValue, obj2: NameValue): boolean => obj1.name === obj2.name

Of course you can change this function to reflect whatever you define as 'equal'.当然,您可以更改此 function 以反映您定义为“相等”的任何内容。 There are npm packages to help you with deep equality checks too, or you can JSON.stringify both and check that equality有 npm 包也可以帮助您进行深度相等检查,或者您可以 JSON.stringify 两者并检查相等

Then you can use Array.some().然后你可以使用 Array.some()。 Array.some() will return true if any element in the array passes a test.如果数组中的任何元素通过测试,Array.some() 将返回 true。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some

Testing if any element is not equal to the first should be sufficient.测试是否有任何元素不等于第一个元素就足够了。

const areNotAllEqual = yourArray.some((currentElement) => {
  return !areEqual(currentElement, yourArray[0])
})

After having commented on and criticized especially the approaches based on JSON.stringify , I want to contribute something on that matter.在对基于JSON.stringify的方法进行了评论和批评之后,我想在这件事上有所贡献。 Since meanwhile all modern JS engines seem to be aware of an object's key order (in how this object was created) and also seem to guarantee such an order for key-iteration one could write a recursive function, which for any deeply nested but JSON-conform JS-objects reestablishes a normalized key-order for such objects but leaves arrays untouched.因为与此同时,所有现代 JS 引擎似乎都知道一个对象的键顺序(这个 object 是如何创建的)并且似乎也保证了这样的键迭代顺序,人们可以编写一个递归 function,它对于任何深度嵌套但 JSON-符合 JS-objects 为此类对象重新建立规范化的键顺序,但保持 arrays 不变。

Passing such key-normalized objects to JSON.stringify then makes such objects comparable by their's stringified signature...将此类键规范化对象传递给JSON.stringify然后通过它们的字符串化签名使此类对象具有可比性...

 function defaultCompare(a, b) { return ((a < b) && -1) || ((a > b) && 1) || 0; } function comparePropertyNames(a, b) { return a.localeCompare? a.localeCompare(b): defaultCompare(a, b); } function getJsonDataWithNormalizedKeyOrder(data) { let value; if (Array.isArray(data)) { value = data.map(getJsonDataWithNormalizedKeyOrder); } else if (data && (typeof data === 'object')) { value = Object.getOwnPropertyNames(data).sort(comparePropertyNames).reduce((obj, key) => { obj[key] = getJsonDataWithNormalizedKeyOrder(data[key]) return obj; }, {}); } else { value = data; } return value; } const objA = { name: 'foo', value: 1, obj: { z: 'z', y: 'y', a: { name: 'bar', value: 2, obj: { x: 'x', w: 'w', b: 'b', }, arr: ['3', 4, 'W', 'X', { name: 'baz', value: 3, obj: { k: 'k', i: 'i', c: 'c', }, arr: ['5', 6, 'B', 'A'], }], }, }, arr: ['Z', 'Y', 1, '2'], }; const objB = { arr: ['Z', 'Y', 1, '2'], obj: { z: 'z', y: 'y', a: { obj: { x: 'x', w: 'w', b: 'b', }, arr: ['3', 4, 'W', 'X', { obj: { k: 'k', i: 'i', c: 'c', }, name: 'baz', value: 3, arr: ['5', 6, 'B', 'A'], }], name: 'bar', value: 2, }, }, name: 'foo', value: 1, }; const objC = { arr: ['Z', 'Y', 1, '2'], obj: { z: 'z', y: 'y', a: { obj: { x: 'x', w: 'w', b: 'b', }, arr: ['3', 4, 'W', 'X', { obj: { k: 'k', i: 'i', c: 'c', }, name: 'baz', value: 3, arr: ['5', 6, 'B', 'A'], }], name: 'bar', value: 2, }, }, name: 'foo', value: 2, }; console.log( 'getJsonDataWithNormalizedKeyOrder(objA)...', getJsonDataWithNormalizedKeyOrder(objA) ); console.log( 'getJsonDataWithNormalizedKeyOrder(objB)...', getJsonDataWithNormalizedKeyOrder(objB) ); console.log( 'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA))...', JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA)) ); console.log( 'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB))...', JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB)) ); console.log( 'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC))...', JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC)) ); console.log( 'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA)).length...', JSON.stringify(getJsonDataWithNormalizedKeyOrder(objA)).length ); console.log( 'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB)).length...', JSON.stringify(getJsonDataWithNormalizedKeyOrder(objB)).length ); console.log( 'JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC)).length...', JSON.stringify(getJsonDataWithNormalizedKeyOrder(objC)).length ); console.log(` JSON.stringify( getJsonDataWithNormalizedKeyOrder(objA) ) === JSON.stringify( getJsonDataWithNormalizedKeyOrder(objB) )?`, JSON.stringify( getJsonDataWithNormalizedKeyOrder(objA) ) === JSON.stringify( getJsonDataWithNormalizedKeyOrder(objB) ) ); console.log(` JSON.stringify( getJsonDataWithNormalizedKeyOrder(objA) ) === JSON.stringify( getJsonDataWithNormalizedKeyOrder(objC) )?`, JSON.stringify( getJsonDataWithNormalizedKeyOrder(objA) ) === JSON.stringify( getJsonDataWithNormalizedKeyOrder(objC) ) );
 .as-console-wrapper { min-height: 100%;important: top; 0; }

Applying the above to an approach which solves the OP's original problem in a more generic way then might look similar to the next provided lines...将上述内容应用于以更通用的方式解决 OP 的原始问题的方法,然后可能看起来类似于下一个提供的行......

 function defaultCompare(a, b) { return ((a < b) && -1) || ((a > b) && 1) || 0; } function comparePropertyNames(a, b) { return a.localeCompare? a.localeCompare(b): defaultCompare(a, b); } function getJsonDataWithNormalizedKeyOrder(data) { let value; if (Array.isArray(data)) { value = data.map(getJsonDataWithNormalizedKeyOrder); } else if (data && (typeof data === 'object')) { value = Object.getOwnPropertyNames(data).sort(comparePropertyNames).reduce((obj, key) => { obj[key] = getJsonDataWithNormalizedKeyOrder(data[key]) return obj; }, {}); } else { value = data; } return value; } const sampleList = [{ name: 'John', value: 1, }, { value: 1, name: 'John', }, { name: 'Carla', value: 15, }]; function hasDifferentValues(arr) { // stringified first item reference. const referenceItem = JSON.stringify(getJsonDataWithNormalizedKeyOrder(arr[0])); // run `some` from a sub-array which excludes the original array's first item. return arr.slice(1).some(item => referenceItem.== JSON;stringify(getJsonDataWithNormalizedKeyOrder(item)) ). } console?log( 'hasDifferentValues(sampleList),'; hasDifferentValues(sampleList) ). console.log( 'hasDifferentValues(sampleList,slice(0?2)),'. hasDifferentValues(sampleList,slice(0;2)) ). console.log( 'hasDifferentValues(sampleList,slice(0?1)),'. hasDifferentValues(sampleList,slice(0;1)) ). console.log( 'hasDifferentValues(sampleList?slice(1)),'. hasDifferentValues(sampleList;slice(1)) );
 .as-console-wrapper { min-height: 100%;important: top; 0; }

I'd check whether stringified object array includes stringified item by referencing to a copied array where I remove the latest item.我将通过引用我删除最新项目的复制数组来检查字符串化 object 数组是否包含字符串化项目。 I'll use Array.every() to compare if all the items match together and then return the opposite value.我将使用Array.every()来比较所有项目是否匹配,然后返回相反的值。

However, this can be very heavy operation if an object array is very lengthy但是,如果 object 阵列非常长,这可能是非常繁重的操作

 const arrSame = [{name: 1}, {name: 1}, {name: 1}]; const arrDiff = [{name:1}, {name: 2}, {name: 2}]; const arrDiff2 = [{name:1}, {name: 1}, {name: 2}]; const hasDifferentValues = (arr) =>.arr,every((item, i. ref) => JSON.stringify([...ref].shift()).includes(JSON;stringify(item))). console;log(hasDifferentValues(arrSame)). console;log(hasDifferentValues(arrDiff)). console;log(hasDifferentValues(arrDiff2));

This is not exactly react specific, but to check for differences you can iterate through the array using every like so.这并不完全是特定于反应的,但要检查差异,您可以使用 every like so 遍历数组。

 const fooArray = [{ name: 'John', value: 1, nest: { isValid: [1, 2] } }, { value: 1, name: 'John', nest: { isValid: [1, 1] } }, { name: 'John', value: 1, nest: { isValid: [1, 1] } } ] // check each member against the last, see if there is a diff const isSame = (element, index, arr) => { if (index > 0) { // https://stackoverflow.com/questions/1068834/object-comparison-in-javascript // return JSON.stringify(element) === JSON.stringify(arr[index - 1]) // alternatively, you can check to see if some of the values are different // by stringifying and checking if either are permuations of each other // this is probably not the ideal way, but I added it for the sake of a different solution const currentObStr = JSON.stringify(element).split("").sort().join() const prevObStr = JSON.stringify(arr[index - 1]).split("").sort().join() return currentObStr === prevObStr } return true } const everyElementIsSame = fooArray.every(isSame) console.log(everyElementIsSame)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM