スマートフォン向けのアプリケーションで例えば
- 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