LoginSignup
9
9

More than 5 years have passed since last update.

RubyでJSONな配列を比較して差分を取得したい

Posted at

スマートフォン向けのアプリケーションで例えば

  • Web APIから取得したJSON
  • あらかじめローカルにあるJSON

という2つを比較して、差分となるJSONだけを取得する方法を過去何度か調べて実装してました。

その時はTitaniumでアプリ開発してて、JavaScriptでの実装を考えていたのですが、今回、Rubyでの実装についてちょっと考える必要があって、近い将来また同じことに悩みそうなのでQiitaにまとめておくことにします。

今回のサンプルのデータ構造

ベースとなるJSONが以下のようなものだとします

master_junre= [
  {id:1,name:"japanese"},
  {id:2,name:"sushi"},
  {id:3,name:"kaisen"},
  {id:4,name:"soba"},
  {id:5,name:"udon"}
]

ベースとなるJSONから除外したいJSONが以下のようなものだとします。

exclude_junre= [
  {id:3,name:"kaisen"}
]

比較するための前処理

マスターデータの中から除外したいデータを抜き出す前処理としてIDをキーにした配列をそれぞれ生成した上で配列の差集合を実施します。

配列の差集合はRubyやJavaScriptでの配列の差集合・和集合・積集合が参考になりました

master_junre_ids = master_junre.map{|o|o[:id]}
exclude_junre_ids = exclude_junre.map{|o|o[:id]}
diff_result = master_junre_ids - exclude_junre_ids

この段階で変数diff_resultに格納されてる値を確認するとこのようになってます。

irb(main):059:0> diff_result
=> [1, 2, 4, 5]

仕上げの処理

配列diff_resultに含まれるIDだけピックアップしていきます。

r = []
master_junre.each do |o|
  r.push(o) if diff_result.include?(o[:id])
end

上記処理で、比較した結果が配列rに格納されてるので、試しに、確認すると以下のように意図した値が格納されてます

irb(main):088:0> r
=> [{:id=>1, :name=>"japanese"}, {:id=>2, :name=>"sushi"}, {:id=>4, :name=>"soba"}, {:id=>5, :name=>"udon"}]

ソースコード全体

念のため以下貼っておきます


master_junre= [
  {id:1,name:"japanese"},
  {id:2,name:"sushi"},
  {id:3,name:"kaisen"},
  {id:4,name:"soba"},
  {id:5,name:"udon"}
]

exclude_junre= [
  {id:3,name:"kaisen"}
]

master_junre_ids = master_junre.map{|o|o[:id]}
exclude_junre_ids = exclude_junre.map{|o|o[:id]}
diff_result = master_junre_ids - exclude_junre_ids

r = []
master_junre.each do |o|
  r.push(o) if diff_result.include?(o[:id])
end
9
9
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
9