如何比较两个具有相同属性但顺序不同的JSON?

61

我尝试比较这两个JSON对象:

<input type="hidden" id="remoteJSON" name="remoteJSON" value='{"allowExternalMembers": "false", "whoCanJoin": "CAN_REQUEST_TO_JOIN"}' /><br />
<input type="hidden" id="localJSON" name="localJSON" value='{"whoCanJoin": "CAN_REQUEST_TO_JOIN", "allowExternalMembers": "false"}' /><br />

我使用JavaScript获取了数值并尝试进行比较:JSON.stringify(remoteJSON) == JSON.stringify(localJSON)但是返回了false:似乎属性的顺序很重要。

我甚至尝试了这个解决方案中的深度比较,但总是得到false的结果。

是否有一种快速的方法使用jQuery(如用于比较JSON的库)来解决这个问题?


你应该阅读这篇文章:https://dev59.com/MHVC5IYBdhLWcg3w1E1q。 - Güven Altuntaş
你能展示一下你如何进行深度比较吗? - Andrew Shepherd
5
“而且总是得到错误的返回值”---不,它并不会。如果那个函数返回了 false,那就意味着你的对象确实是不同的。http://jsfiddle.net/pyLqhujo/ - zerkms
@zerkms:我以前比较字符串而不是对象,所以现在返回true语句就没问题了...+1 - Drwhite
抱歉,那是我的错。 - Güven Altuntaş
16个回答

49

Lodash _.isEqual 让您可以做到这一点:

var
remoteJSON = {"allowExternalMembers": "false", "whoCanJoin": "CAN_REQUEST_TO_JOIN"},
    localJSON = {"whoCanJoin": "CAN_REQUEST_TO_JOIN", "allowExternalMembers": "false"};
    
console.log( _.isEqual(remoteJSON, localJSON) );
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>


对于React,请确保您添加 import _ from 'lodash'; - DocAsh59

28

Lodash isEqual()方法是比较两个JSON对象的最佳方式。

它不考虑对象中键的顺序,检查对象的相等性。例如:

const object1 = {
  name: 'ABC',
  address: 'India'
};
    
const object2 = {
  address: 'India',
  name: 'ABC'
};
    
JSON.stringify(object1) === JSON.stringify(object2)
// false
    
_.isEqual(object1, object2)
// true

参考资料- https://lodash.com/docs/#isEqual

如果序列不会更改,那么与Lodash的 isEqual() 方法相比,JSON.stringify()的速度将更快。

参考资料- https://www.measurethat.net/Benchmarks/Show/1854/0/lodash-isequal-test


这是一个不好的解决方案,因为如果对象键的顺序混乱或未排序,则无法正常工作。 - IGHOR

11

DeepCompare method to compare two json objects..

deepCompare = (arg1, arg2) => {
  if (Object.prototype.toString.call(arg1) === Object.prototype.toString.call(arg2)){
    if (Object.prototype.toString.call(arg1) === '[object Object]' || Object.prototype.toString.call(arg1) === '[object Array]' ){
      if (Object.keys(arg1).length !== Object.keys(arg2).length ){
        return false;
      }
      return (Object.keys(arg1).every(function(key){
        return deepCompare(arg1[key],arg2[key]);
      }));
    }
    return (arg1===arg2);
  }
  return false;
}

console.log(deepCompare({a:1},{a:'1'})) // false
console.log(deepCompare({a:1},{a:1}))   // true


3

我修改并适应了这个教程的代码,写了一个函数来深度比较两个JS对象。

const isEqual = function(obj1, obj2) {
    const obj1Keys = Object.keys(obj1);
    const obj2Keys = Object.keys(obj2);

    if(obj1Keys.length !== obj2Keys.length) {
        return false;
    }

    for (let objKey of obj1Keys) {
        if (obj1[objKey] !== obj2[objKey]) {
            if(typeof obj1[objKey] == "object" && typeof obj2[objKey] == "object") {
                if(!isEqual(obj1[objKey], obj2[objKey])) {
                    return false;
                }
            } 
            else {
                return false;
            }
        }
    }

    return true;
};

该函数比较两个对象相同键的对应值,若这两个值都是对象,则使用递归深度比较它们。

希望这可以帮到你。


3
在JavaScript中比较两个JSON字符串的简单方法
var obj1 = {"name":"Sam","class":"MCA"};
var obj2 = {"class":"MCA","name":"Sam"};

var flag=true;

if(Object.keys(obj1).length==Object.keys(obj2).length){
    for(key in obj1) { 
        if(obj1[key] == obj2[key]) {
            continue;
        }
        else {
            flag=false;
            break;
        }
    }
}
else {
    flag=false;
}
console.log("is object equal"+flag);

5
这只适用于基本数据类型。如果 obj[key]obj2[key] 具有嵌套对象,则此方法将失败,因为对象是按照它们的引用进行比较的。 - The Witness

3

这段代码可以独立于参数对象的顺序验证json。

var isEqualsJson = (obj1,obj2)=>{
    keys1 = Object.keys(obj1);
    keys2 = Object.keys(obj2);

    //return true when the two json has same length and all the properties has same value key by key
    return keys1.length === keys2.length && Object.keys(obj1).every(key=>obj1[key]==obj2[key]);
}

var obj1 = {a:1,b:2,c:3};
var obj2 = {a:1,b:2,c:3}; 

console.log("json is equals: "+ isEqualsJson(obj1,obj2));
alert("json is equals: "+ isEqualsJson(obj1,obj2));


这只是说明是否相等。我们如何列出任何不同的键值? - shyam yadav
这只会深入一个层级。 - MalcolmOcean

1

lodash可以使用,甚至已经测试过适用于Angular 5,http://jsfiddle.net/L5qrfx3x/

var remoteJSON = {"allowExternalMembers": "false", "whoCanJoin": 
   "CAN_REQUEST_TO_JOIN"};
var localJSON = {"whoCanJoin": "CAN_REQUEST_TO_JOIN", 
  "allowExternalMembers": "false"};

 if(_.isEqual(remoteJSON, localJSON)){
     //TODO
    }

它可以工作,如果要在Angular中安装,请按照this的链接进行操作。


1

这个函数适用于具有简单基元的对象:

function compareObjects(o1, o2) {
  const normalizedObj1 = Object.fromEntries(Object.entries(o1).sort(([k1], [k2]) => k1. localeCompare(k2)));
  const normalizedObj2 = Object.fromEntries(Object.entries(o2).sort(([k1], [k2]) => k1. localeCompare(k2)));
  return JSON.stringify(normalizedObj1) === JSON.stringify(normalizedObj2);
}

compareObjects({a: 1, b: 2}, {b: 2, a: 1}); // true


如果对象包含嵌套对象,则无法正常工作,因为我们需要递归地对它们进行规范化。

1
注意:此实现仅适用于不包含循环引用的JSON对象。如果您的JSON对象可能包含循环引用,则需要相应地修改实现。

function deepCompare(obj1, obj2) {
  // compare types
  if (typeof obj1 !== typeof obj2) {
    return false;
  }

  // compare properties recursively
  if (typeof obj1 === 'object') {
    if (Array.isArray(obj1) !== Array.isArray(obj2)) {
      return false;
    }
    if (Array.isArray(obj1)) {
      if (obj1.length !== obj2.length) {
        return false;
      }
      for (let i = 0; i < obj1.length; i++) {
        if (!deepCompare(obj1[i], obj2[i])) {
          return false;
        }
      }
    } else {
      const keys1 = Object.keys(obj1);
      const keys2 = Object.keys(obj2);
      if (keys1.length !== keys2.length) {
        return false;
      }
      for (const key of keys1) {
        if (
          !Object.prototype.hasOwnProperty.call(obj2, key) ||
          !deepCompare(obj1[key], obj2[key])
        ) {
          return false;
        }
      }
    }
  } else {
    // compare primitive values
    if (obj1 !== obj2) {
      return false;
    }
  }

  // objects are equal
  return true;
}


const json1 = '{"name": "John", "age": 30, "address": {"street": "123 Main St", "city": "Anytown"}}';
const json2 = '{"name": "John", "age": 30, "address": {"street": "123 Main St", "city": "Anytown"}}';

const obj1 = JSON.parse(json1);
const obj2 = JSON.parse(json2);

console.log(deepCompare(obj1, obj2));


0
如果您正在尝试使用与我相同的目标比较这两个对象:即仅反序列化有效对象,那么我建议您使用以下方法:
using Newtonsoft.Json;

try
{
    var myObj = JsonConvert.DeserializeObject<**YourTargetObjectType**>(jsonString, new JsonSerializerSettings
    {
        MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
        MissingMemberHandling = MissingMemberHandling.Error
    });
}catch (MissingMemberException mme)
{
    
    throw;
}

如果捕获到错误,那么您的对象就不属于YourTargetObjectType。否则,一切都很顺利,您可以对第二个对象执行相同的操作。

使用MissingMemberHandling的JsonSerializerSetings可以解决问题。在mme异常对象中,您可以检查哪个属性失败了。这将验证额外的属性、缺少的属性和/或拼写错误的属性。

因此,在您的情况下,您应该有一个对象作为参考,以比较两个对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接