15

I am trying to compare json_str1 and json_str2, here it should return true as all elements in json_str1 are present in json_str2.

For now I am doing this the long way like this

json_str1 = '{"0":"a","1":"b","2":"c"}';
json_str2 = '{"0":"c","1":"b","2":"a"}';

json_obj1 = $.parseJSON(json_str1);
json_obj2 = $.parseJSON(json_str2);

arr1 = $.map(json_obj1, function(el) { return el });
arr2 = $.map(json_obj2, function(el) { return el });

if($(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0)
    alert("equal");
else
    alert("not equal");

How could I make it short and simple, without converting the objects into an array ?

https://jsfiddle.net/kq9gtdr0/

Niklesh Raut
  • 34,013
  • 16
  • 75
  • 109
  • 1
    Shouldn't it be `JSON.stringify(json_str1) === JSON.stringify(json_str2) `. [Also see how to determine equality for two javascript objects](http://stackoverflow.com/questions/201183/how-to-determine-equality-for-two-javascript-objects) – Shubh Feb 23 '16 at 10:25
  • Looks like you are just trying to verify if the two JSONs have the same keys... Is this an accurate assumption? – Lix Feb 23 '16 at 10:26
  • 1
    If you only want to check if all characters in json_str1 is present in json_str2, you can run a simple sort on JSON.stringify(json_str1).sort(), because json objects might not be stringified in order. – sarker306 Feb 23 '16 at 10:27
  • 1
    @Shubh, it will fail if json has different order of same key-values than other json object. – Ganesh Nemade Feb 23 '16 at 10:28
  • @Lix if 'a','b'&'c' present in both json in any order it should be true. – Niklesh Raut Feb 23 '16 at 10:34
  • @LearningMode - so you are talking about the values? Not the keys? – Lix Feb 23 '16 at 10:36
  • @Lix yes I am trying to compare json values – Niklesh Raut Feb 23 '16 at 10:38
  • 1
    Maybe it makes sense to ask why he is doing this, to find an even simpler way. – dec Feb 24 '16 at 07:36
  • Possible duplicate of [Object comparison in JavaScript](http://stackoverflow.com/questions/1068834/object-comparison-in-javascript) – Rajesh Feb 24 '16 at 08:00
  • You can refer following post: [Compare arrays in javascript](http://stackoverflow.com/questions/7837456/how-to-compare-arrays-in-javascript). Also, just a pointer. I know its little late but if your code is working properly and if objective of this question is optimization/improvements, you should post it on [CodeReview](http://codereview.stackexchange.com/) – Rajesh Feb 24 '16 at 12:22
  • 1
    Since no one said it : there is no such thing as JSON objects in javascript. There are instead JS objects, which can be displayed as strings with the **J**ava**S**cript **O**bject **N**otation. So what you want, since you have parsed the JSON strings into JS objects, is to compare two JS objects. – Aaron Feb 25 '16 at 10:50
  • You said *all element*, but JavaScript objects do not have "elements". Do you mean values? Why do you not want to convert them into arrays, since what you are essentially asking if whether the array of values from one object is equivalent to the array of values from another? –  Feb 25 '16 at 18:25
  • Do you want to values in the two objects to match exactly, or do you want all values in the first to be found in the second (but with the second possibly holding additional values)? –  Feb 26 '16 at 01:18
  • @torazaburo Thanks for your ans, and updating my question topic, I wanted to check all values in the first to be found in the second one. – Niklesh Raut Feb 26 '16 at 04:43
  • Sorry, but this is a poorly worded question. You say that you 'check all values in the first to be found in the second one.' But your code example checks for equality, by checking that things in the first are in the second and that things in the second are in the first. Also, you don't seem to know what JSON and JS objects actually are. You refer to `JSON values` in a way that doesn't make sense. JSON is parsed into JS objects. JS objects contain keys, and each key has a value. – Tony Mar 03 '16 at 06:56

8 Answers8

13

Use the following code:

Object.keys(json_obj1) . every(k1 => 
  Object.keys(json_obj2) . some(k2 =>
    json_obj1[k1] === json_obj2[k2]
  )
);

In English:

Every key k1 in json_obj1 satisfies the condition that some key k2 in json_obj2 satisifies the condition that the value of json_obj1 with key k1 is equal to the value of json_obj2 with key k2.

Or in more conversational English:

Every value in the first object matches some value in the second.

  • Why does `Object.keys(json_str1)` return an array having 25 properties `["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24"]` ? Instead of the 3 properties that `json_str1` contains ; e.g.; `["0", "1", "2"]` ? – guest271314 Feb 25 '16 at 18:51
  • `json_str1` is a string. It contains no properties. It's just a string. The console will report a property for each character in the string. You want to examine the properties of `json_obj1`, which is a proper JavaScript object. –  Feb 25 '16 at 18:59
  • Your solution will return `true` for `json_str1 = '{"0":"aa","1":"b","2":"c"}'; json_str2 = '{"0":"c","1":"b","2":"a"}';` – guest271314 Feb 25 '16 at 19:02
  • No, it returns false. –  Feb 25 '16 at 19:03
  • _"No, it returns false."_ Can you create a jsfiddle to demonstrate ? Appeared to return `true` , here – guest271314 Feb 25 '16 at 19:05
  • Your fiddle is broken. You're taking the keys of `json_str1` instead of `json_obj1`. `json_str1` is a string and has no keys. –  Feb 25 '16 at 19:11
  • _"Your fiddle is broken. You're taking the keys of json_str1 instead of json_obj1"_ ? Used the `js` that you posted. It is your `js` that must be broken. – guest271314 Feb 25 '16 at 19:12
  • 1
    No. My JS said `Object.keys(json_obj1)`. Your fiddle says `Object.keys(json_str1)`. Note carefully the difference between `json_str1`, which is a string, and `json_obj1`, which is a JavaScript object created by parsing that string. Please see corrected fiddle at https://jsfiddle.net/cLhs1bbc/1/. –  Feb 25 '16 at 19:13
  • Looks like exactly what I was looking for :) – Niklesh Raut Feb 26 '16 at 04:40
  • This answer does not do what was asked, it compares the values of each key in the objects. If you look at the example JSON strings, the question is obviously asking for a solution that checks the keys but ignores the values. Also, the `. some` portion is overkill, it is not needed. It happens to work on the example string because they both happen to have "1":"b", and your incorrect `.some` returns true due to that. Instead, try the strings '{"0":"a","1":"b","2":"c"}' and '{"0":"d","1":"e","2":"f"}' – Tony Mar 03 '16 at 07:28
  • That's odd, because in the comments, the OP responded to the question *so you are talking about the values? Not the keys?* by saying *yes I am trying to compare json **values**.* Furthermore, if you look at his jQuery solution, note that he is retrieving the **values** into arrays before trying to compare them (note that jQuery's `map` calls the callback with the first parameter being the value, not the key). –  Mar 03 '16 at 07:43
2

Using lodash

var _ = require('lodash');

function compareValues(jstr1, jstr2) {
  return _.isEqual(_.valuesIn(JSON.parse(jstr1)).sort(), _.valuesIn(JSON.parse(jstr2)).sort());
}

json_str1 = '{"0":"a","1":"b","2":"c"}';
json_str2 = '{"0":"c","1":"b","2":"a"}';

console.log(compareValues(json_str1, json_str2));
manonthemat
  • 6,101
  • 1
  • 24
  • 49
1

There is short and easy accurate way to this.

You can use a third party but extremely popular utility library called Lodash. Chaining functions you can check for equality.

  1. First parse both JSON into objects
  2. Then use _.values() to extract the values of all keys of each into separate arrays
  3. Find difference of two arrays. If its an empty array then both of them are equal.

You can chain all the steps into one statement like:

_.isEmpty(_.difference(_.values(json_obj1), _.values(json_obj2)))

Example: https://jsfiddle.net/kq9gtdr0/4/

For more information:

https://lodash.com/docs#values

https://lodash.com/docs#difference

https://lodash.com/docs#isEmpty

You can include the library from CDN(https://cdn.jsdelivr.net/lodash/4.5.1/lodash.min.js) or download and use it as normal script. Lodash offers plenty of useful utility functions that makes JS programming a lot easier. You better try it out.

Nidhin David
  • 2,426
  • 3
  • 31
  • 45
  • Thanks for your reply. But I am trying if 'a','b'&'c' present in both json in any order it should be true – Niklesh Raut Feb 23 '16 at 11:52
  • @LearningMode You mean if all the values in obj1 is in obj2 but for different keys you want those two objects to be equal? – Nidhin David Feb 24 '16 at 05:17
  • Yes, I did it but in long way. Trying to make it short. – Niklesh Raut Feb 24 '16 at 05:40
  • I won't specify any technical way of doing this, I'm not that good in JavaScript, but I think you should be aware that json format doesn't specify the order of the key value pairs. So { 'a' : 1, 'b' : 2} and {'b' : 2, 'a' : 1} are actually the same document. Moreover in many languages they are represented by Unordered Map-like structures so, in general you shouldn't count on order of those. – Mark Bramnik Feb 24 '16 at 06:25
  • @MarkBramnik He is talking about the values only. Its not like { 'a' : 1, 'b' : 2} and {'b' : 2, 'a' : 1} its like 1 and 2 is present in the other object the result should be true even for different keys like { 'a' : 1, 'b' : 2} and {'a' : 2, 'b' : 1} must be true – Nidhin David Feb 24 '16 at 06:42
1

If you prefer using libraries, then you could use underscore isMatch

_.isMatch(object, properties)

Tells you if the keys and values in properties are contained in object.

nilesh
  • 14,131
  • 7
  • 65
  • 79
0

Extending the awesome answer by @user663031, in case you need to do deep comparison, here's code that works:

export function objectOneInsideObjectTwo(jsonObj1: any, jsonObj2: any): boolean {
  return Object.keys(jsonObj1).every((k1) => {
    if (parseType(jsonObj1[k1]) === 'dict') {
      return objectOneInsideObjectTwo(jsonObj1[k1], jsonObj2[k1]);
    }
    if (parseType(jsonObj1[k1]) === 'array') {
      const results: boolean[] = [];
      jsonObj1[k1].forEach((o: any, i: number) => {
        if (parseType(o) === 'dict') {
          results.push(objectOneInsideObjectTwo(o, jsonObj2[k1][i]));
        } else {
          results.push(o === jsonObj2[k1][i]);
        }
      });
      return results.every((r) => r);
    }
    return Object.keys(jsonObj2).some((k2) => jsonObj1[k1] === jsonObj2[k2]);
  });
}

export function parseType<T>(v: T): string {
  if (v === null || v === undefined) {
    return 'null';
  }
  if (typeof v === 'object') {
    if (v instanceof Array) {
      return 'array';
    }
    if (v instanceof Date) {
      return 'date';
    }
    return 'dict';
  }
  return typeof v;
}
ilmoi
  • 1,994
  • 2
  • 21
  • 45
-1

You can try this

var json_str1 = {"0":"a","1":"b","2":"c"};
var json_str2 = {"0":"c","1":"b","2":"a"};
var flag =  1;

if(Object.keys(json_str1).length == Object.keys(json_str2).length){
    Object.keys(json_str1).forEach(function(x){
        if(!json_str2.hasOwnProperty(x) || json_str2[x] != json_str1[x]){
            flag = 0;
            return;
        }                      
    });
}

if(flag)
    alert('equal');
else
    alert('Not Equal');
Atul Agrawal
  • 1,474
  • 5
  • 22
  • 41
-1

If you want to find out if both Objects have the same keys there is no way to do this without at least converting the keys of both Objects to an array with Object.keys or looping through both Objects!

The reason is simple: It's clear that you have to compare the number of keys of both Objects and the only way to do this is by looping through all properties or Object.keys.

So I think the shortest way to do this is:

json_obj1 = JSON.parse('{"0":"a","1":"b","2":"c"}');
json_obj2 = JSON.parse('{"0":"c","1":"b","2":"a"}');

keys_1 = Object.keys(json_obj1);
keys_2 = Object.keys(json_obj2);

if(keys_1.length === keys_2.length && keys_1.every(key => keys_2.indexOf(key) >= 0)) {
    alert('equal')
} else {
    alert('not equal')
}

If you only want to check if all keys from json1 are present in json2 you can do:

json_obj1 = JSON.parse('{"0":"a","1":"b","2":"c"}');
json_obj2 = JSON.parse('{"0":"c","1":"b","2":"a"}');
if(Object.keys(json_obj1).every(key => key in json_obj2)) {
  alert('equal');
} else {
  alert('not equal');
}
Lux
  • 17,835
  • 5
  • 43
  • 73
  • Your code returns "not equal", but the correct answer is "equal". –  Feb 25 '16 at 18:26
  • `There is no way to do this without at least converting the keys of both Objects to an array with Object.keys or looping through both Objects!` - Ermmmm, I think you'll find I did it :D – Adrian Lynch Feb 25 '16 at 19:09
  • @AdrianLynch what do you think does your `.filter` do? – Lux Feb 26 '16 at 07:49
-1

In your question and comments you indicate you are only looking to verify that "all elements in json_str1 are present in json_str2". Your example code doesn't just do that, it checks for the complete equality of keys by testing if all the keys (not values) in the first object are in the second object AND all the keys in the second object are in the first object. By looking at your code, i assume that when you say "elements" you mean keys.

All that aside, this might help:

// Your first few lines of code

json_str1 = '{"0":"a","1":"b","2":"c"}';
json_str2 = '{"0":"c","1":"b","2":"a"}';

json_obj1 = $.parseJSON(json_str1);
json_obj2 = $.parseJSON(json_str2);

// My new code

var values1 = Object.keys(json_obj1).map(key => json_obj1[key]);
var values2 = Object.keys(json_obj2).map(key => json_obj2[key]);

// Check if every key in the first object is in the second object.
values1.every(k1 => values2.indexOf(k1) >= 0);

// OR

// Check for equality of keys by checking both directions.
values1.every(k1 => values2.indexOf(k1) >= 0) && values2.every(k2 => values1.indexOf(k2) >= 0);

That's 2 lines to get the keys, and one line to check. You only need one of those two checks.

Tony
  • 953
  • 1
  • 10
  • 22
  • But the line from the OP's solution `arr1 = $.map(json_obj1, function(el) { return el });` returns an array of **values**, **NOT** keys. `$.map` passes the **value** as the first parameter to the callback. So what he is doing is **not** the same as `Object.keys`. You are also misinterpreting the part of the question that say *it should return true as all elements in `json_str1` are present in `json_str2`*, It does not say the sets must be identical; it merely says that the second set must **contain** the first. Hence, it is unnecessary and wrong to check in both directions. –  Mar 03 '16 at 07:52
  • @torazaburo Valid point about the values instead of keys. I don't use jQuery and misinterpreted what `$.map` was doing. However, the start of my question actually addressed the **contains** issue. He **says** he wants to check if the second set contains the first, but the example code in the question does not do that, it checks equality. `if($(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0)` I gave an example of both solutions because the question is not consistent with itself. – Tony Mar 05 '16 at 01:01
  • Editing answer to reflect comparing **values** and not **keys**. – Tony Mar 05 '16 at 01:03
  • Lesson learned, don't try to answer a poorly written question. – Tony Mar 05 '16 at 01:15