RubyでJSONを要素の順番によらず同一判定したい


RubyでJSONデータを各要素の順番によらず、同じ要素が含まれていれば（連想配列の場合はキーと値の組み合わせが同じであれば）同一と判定したいと思っています。

以下のようなコードを考えていますが、もっとシンプルなやり方があれば教えてください。 （目的は同一判定なのでソート以外のやり方でも構いません）

[code]

    def json_sort(json)
      # jsonから生成したRubyオブジェクトを再帰的にソートする
      case json
      when Array
        # 配列の場合はソートし、json_sortを各要素に適用
        json.sort.map{|v|json_sort(v)}
      when Hash
        # 連想配列の場合はキーでソートした上でjson_sortを各要素に適用
        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) #=> 順番が違っても同一と判定したい
    
[/code]




Arrayを順番によらず同一視したいということは、RubyのArrayに展開されるのが間違っていると言う事だと思います。この場合はSetが望むものではないでしょうか？

array_classオプションで配列をどのクラスにするか指定できる(<http://docs.ruby-
lang.org/ja/2.1.0/method/JSON=3a=3aParser/s/new.html>)ので、それを使う事で以下のようにかけます。

[code]

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

ただし、Setだと`[1,1,2]`が`[1,2]`と同じに扱われてしまうので、それだと不味い場合は、

[code]

    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)
    
[/code]

とすると質問と同じ結果を出すコードになりますし、またはSetから入力をvalidateするクラスを作ってそれを用いるのもありえると思います。

