I want Ruby to identify JSON regardless of the order of the elements.

Asked 1 years ago, Updated 1 years ago, 84 views

I would like Ruby to determine that JSON data is identical if it contains the same elements (in the case of associative arrays, if the key and value combinations are the same).

I am thinking of the following code, but if there is a simpler way, please let me know. (The purpose is the same, so you can do something other than sort.)

def json_sort(json)
  # recursively sort Ruby objects generated from json
  case json
  when Array
    # Sort for arrays and apply json_sort to each element
    json.sort.map { | v | json_sort(v)}
  when Hash
    # For associative arrays, sort by key and apply json_sort to each element
    Hash [json.sort.map { | (k,v) | [k,json_sort(v)]}]
  else;json
  end
end

a=JSON.parse('{"a":1,"b":[1,2]}')
b = JSON.parse ('{"b":[2,1], "a":1}')
json_sort(a)==json_sort(b)#=> I want to judge that it is the same even if the order is different

ruby json

2022-09-30 20:27

3 Answers

If you want to identify the arrays regardless of order, I think it is wrong to develop them in Ruby's Array.In this case, isn't it what Set wants?

The array_class option allows you to specify which class the array should be in (http://docs.ruby-lang.org/ja/2.1.0/method/JSON=3a=3aParser/s/new.html), so you can use it to do the following:

require 'set'
a=JSON.parse('{"a":1,"b":[1,2]}', array_class:Set)
b=JSON.parse('{"b":[2,1], "a":1}', array_class:Set)
pa,b,a==b

However, with Set, [1,1,2] is treated the same as [1,2], so if that doesn't taste good,

class CustomArray<Array
  def==(a)
    self.sort == a.sort
  end
end
a=JSON.parse('{"a":1,"b":[1,2]}', array_class:CustomArray)
b=JSON.parse('{"b":[2,1], "a":1}', array_class:CustomArray)

If so, the code will produce the same result as the question, or you can create a class to validate the input from Set and use it.


2022-09-30 20:27

I can only show a little bit of the sauce since it's from my smartphone, but

Originally, when comparing Hash with ==, they compare it even if the order is different. So now, Array is a problem (although there may be arguments about whether it's okay to have the same array), and I think JSON might not have complicated objects.(I'm sorry if that assumption doesn't work.)

Therefore, it would be a little simpler to deep copy the original hash and then examine the contents and sort the array destructive as it is now.

The deep copy is

dup_a=Marshal.load(Marshal.dump(a))
dup_b = Marshall.load (Marshal.dump(b))

and so on. And if you sort and compare only the arrays,

 dup_a["b"].sort! 
dup_b["b"].sort!
pdup_a==dup_b

The result is true.

If you functionalize all the sequences in the hash, you end up with the same recursive call as you do now. I think it is possible to simplify the sorting and generation of hash (when Hash part) during recursion.


2022-09-30 20:27

Here are some reference information.
The stackoverflow has the following page:

Searching for "canonical json" on the net also provides information on similar issues.


2022-09-30 20:27

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.