質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • Ruby

    7368questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • JSON

    1120questions

    JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

  • Model

    80questions

    MVCモデルの一部であるModelはアプリケーションで扱うデータとその動作を管理するために扱います。

rubyを用いて、jsonファイルを加工するプログラムを作成したいです。

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 2,405

cDm_48

score 164

rubyを用いて、jsonファイルを加工するプログラムを作成したいです。
やりたいことと致しましては
2つ以上のファイルのjsonファイルをして必要なデータのみ抽出し、
別のファイルとして出力したいです。(テキストファイルなり、csv、json等)

以下にあるファイル名でいうと、
hoge1.jsonファイルの"name":"函館朝市"

をトリガーとし、

hoge2.jsonの
"name":"函館朝市"の"ken"である"北海道"を取得したいです。

そしてテキストファイルに以下のように出力したいです。

ken:北海道
name:函館朝市

実際にやろうとすることは、もっとデータが多いため、複雑になっております。
今回は、あくまでシンプルにするため、このような形態にしております。

そのため別の例を出すと、
"name":"名古屋市"という情報から、
"ken":"名古屋"
というのを取得したりしたいです。


データベースのカラムのような要領で、同じカラムをトリガーとして、関連する情報を
取得するプログラムをrubyで作成したいのですが、やり方がわかりません。

もしご存知の方は、知恵をお貸し頂けないでしょうか?

わかりにくいかと思いますので、質問して頂けると回答致します。


また、私は最近API等に興味があるため、
こういうのを応用して、Jsonを用いて、データの加工などをやっていきたいと考えております。

皆様はそういうのをやられたりしますか?
もしやられていたら、どういうことをなさっていたのかもお答え頂けると嬉しいです。

今後の参考にしていきたいと考えております。

--------------------------

ファイル名;hoge1.json
{
  "marker":[
    {"lat":41.772596,"lng":140.725261,"name":"函館朝市"},
    {"lat":41.796864,"lng":140.756965,"name":"五稜郭"},
    {"lat":41.772912,"lng":140.816231,"name":"函館空港"}
  ]
}


ファイル名;hoge2.json
{
  "hokkaido":[
    {"name":"函館朝市"},
    {"ken":"北海道"},
    {"zinkou":200000}
  ]
}




--------------------

追記

皆様、素晴らしいコード有難う御座います。
こんなコードがかければなと圧巻しております。

さて、追加で大変恐縮ですが、今回、JSONを以下のようにコードの中に直接代入する形で記述されておりますが、hoge1.json といったファイル名をコードに入れて、その中身を markers = JSON.parse というふうにできないでしょうか?

イメージとしては、以下のような感じです。
markers = JSON.parse(hoge1.json)

実際に扱うJSONは30行ほどあり、かつ、日によって増えていくため、
ファイル名から中身を取り出して、パースする処理をしたいです。

もし宜しければ、再度お知恵をお借りできないでしょうか?

何卒宜しくお願いします。


('{ 
"marker":[ 
{"lat":41.772596,"lng":140.725261,"name":"函館朝市"}, 
{"lat":41.796864,"lng":140.756965,"name":"五稜郭"}, 
{"lat":41.772912,"lng":140.816231,"name":"函館空港"},
{"lat":1.000000,"lng":1.000000,"name":"千葉市"}

}')
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+1

hoge2.json の2つ以上のデータがある場合のJSONを教えてもらえますか?


とりあえずこんな感じで。

スクリプト
require 'json'

markers = JSON.parse <<-JSON
{
  "marker":[
    {"lat":41.772596,"lng":140.725261,"name":"函館朝市"},
    {"lat":41.796864,"lng":140.756965,"name":"五稜郭"},
    {"lat":41.772912,"lng":140.816231,"name":"函館空港"}
  ]
}
JSON

prefs = JSON.parse <<-JSON
{
  "hokkaido":[
    {"name":"函館朝市"},
    {"ken":"北海道"},
    {"zinkou":200000}
  ]
}
JSON

mark = markers['marker'][0]
puts "-- mark"
p mark

def find_prefs(name, prefs)
  prefs.each do |label, values|
    values.each do |a_hash|
      a_hash.each do |k, v|
        if k == 'name' && v == name
          return { label => values }
        end
      end
    end
  end
  nil
end

puts "-- search result"
p find_prefs(mark['name'], prefs)
p find_prefs('unknown', prefs)

# --------------------------------
prefs_2 = prefs.map{ |k, v| [k, v.inject(:merge)] }.to_h
puts "=== better structure"
puts "-- all data"
p prefs_2

def find_prefs2(name, prefs_2)
  prefs_2.each do |label, values|
    return values if values['name'] == name
  end
  nil
end

pref_data = find_prefs2(mark['name'], prefs_2)
puts "-- found data"
p pref_data
puts "-- ken"
p pref_data['ken']

結果
-- mark
{"lat"=>41.772596, "lng"=>140.725261, "name"=>"函館朝市"}
-- search result
{"hokkaido"=>[{"name"=>"函館朝市"}, {"ken"=>"北海道"}, {"zinkou"=>200000}]}
nil
=== better structure
-- all data
{"hokkaido"=>{"name"=>"函館朝市", "ken"=>"北海道", "zinkou"=>200000}}
-- found data
{"name"=>"函館朝市", "ken"=>"北海道", "zinkou"=>200000}
-- ken
"北海道"

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/21 22:12

    早速の投稿ありがとうございます。こんなにスラスラ書けてしまうとは圧巻でした。

    >hoge2.json の2つ以上のデータがある場合のJSONを教えてもらえますか?
    今回のhoge.jsonというのは質問用に仮で作ったJSONになります。
    そのため、申し訳ありませんが2つ以上のデータというのは今のところありません。

    しかし、大変わかり易いコードですので、これを元に、私の方でも頑張ってみようと思います。

    追加で恐縮ですが、今回、JSONを以下のようにコードの中に直接代入する形で記述されておりますが、hoge1.json といったファイル名をコードに入れて、その中身を markers = JSON.parse というふうにできないでしょうか?

    イメージとしては、以下のような感じです。
    markers = JSON.parse(hoge1.json)

    実際に扱うJSONは30行ほどあり、かつ、日によって増えていくため、
    ファイル名から中身を取り出して、パースする処理をしたいです。

    もし宜しければ、再度お知恵をお借りできないでしょうか?

    何卒宜しくお願いします。


    JSON
    {
    "marker":[
    {"lat":41.772596,"lng":140.725261,"name":"函館朝市"},
    {"lat":41.796864,"lng":140.756965,"name":"五稜郭"},
    {"lat":41.772912,"lng":140.816231,"name":"函館空港"}
    ]
    }
    JSON

    キャンセル

  • 2015/04/21 22:19

    prefs = JSON.parse(File.read('pref.json'))
    でファイルを読み込めます

    キャンセル

+1

# coding: utf-8
require 'json'
hoge1 = JSON.parse('{ 
  "marker":[ 
    {"lat":41.772596,"lng":140.725261,"name":"函館朝市"}, 
    {"lat":41.796864,"lng":140.756965,"name":"五稜郭"}, 
    {"lat":41.772912,"lng":140.816231,"name":"函館空港"},
    {"lat":1.000000,"lng":1.000000,"name":"千葉市"}
  ] 
}')
hoge2 = JSON.parse('{
  "hokkaido":[ 
    {"name":"函館朝市"}, 
    {"ken":"北海道"}, 
    {"zinkou":200000}
  ],
  "chiba":[ 
    {"name":"千葉市"}, 
    {"ken":"千葉県"}, 
    {"zinkou":100000}
  ]
}')
#hoge1から全てのnameを取得
keys = hoge1['marker'].map{ |e| e['name'] }

#欲しい情報を指定
info = 'ken'

#keysの要素を回しhoge2のnameの一致を検索し出力
keys.map do |key|
  hoge2.select{|k, v| v[0]['name'] == key }.each{ |k, v| puts v[1][info] }
end

#=>北海道
#=>千葉県

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/21 22:15

    早速のご回答ありがとうございます。

    見通しの良いコードで直感的に理解できました。
    投稿してから1時間程度(実際はもっと少ないのかもしれませんが)でこのようなコードがかけるなんて今の自分では理解ができませんでした(笑)

    追加で恐縮ですが、今回、JSONを以下のようにコードの中に直接代入する形で記述されておりますが、hoge1.json といったファイル名をコードに入れて、その中身を markers = JSON.parse というふうにできないでしょうか?

    イメージとしては、以下のような感じです。
    markers = JSON.parse(hoge1.json)

    実際に扱うJSONは30行ほどあり、かつ、日によって増えていくため、
    ファイル名から中身を取り出して、パースする処理をしたいです。

    もし宜しければ、再度お知恵をお借りできないでしょうか?

    何卒宜しくお願いします。


    JSON
    {
    "marker":[
    {"lat":41.772596,"lng":140.725261,"name":"函館朝市"},
    {"lat":41.796864,"lng":140.756965,"name":"五稜郭"},
    {"lat":41.772912,"lng":140.816231,"name":"函館空港"}
    ]
    }
    JSON


    ちなみに追加で恐縮ですが、今回、JSONを以下のようにコードの中に直接代入する形で記述されておりますが、hoge1.json といったファイル名をコードに入れて、その中身を markers = JSON.parse というふうにできないでしょうか?

    イメージとしては、以下のような感じです。
    markers = JSON.parse(hoge1.json)

    実際に扱うJSONは30行ほどあり、かつ、日によって増えていくため、
    ファイル名から中身を取り出して、パースする処理をしたいです。

    もし宜しければ、再度お知恵をお借りできないでしょうか?

    何卒宜しくお願いします。


    ('{
    "marker":[
    {"lat":41.772596,"lng":140.725261,"name":"函館朝市"},
    {"lat":41.796864,"lng":140.756965,"name":"五稜郭"},
    {"lat":41.772912,"lng":140.816231,"name":"函館空港"},
    {"lat":1.000000,"lng":1.000000,"name":"千葉市"}
    ]
    }')

    キャンセル

+1

hoge2.jsonの形式がおかしい気がしますが、200,000 は、200000"200,000"の書き誤りとして、他は書かれた通りだとすると、
require "json"

x1 = JSON.load(IO.read("hoge1.json"))
x2 = JSON.load(IO.read("hoge2.json"))

mark2ken = x2.each_with_object({}){|(x,y),a| a[y[0]["name"]]=y[1]["ken"]}

x1["marker"].each do |mark|
  p mark2ken[mark["name"]]
end

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/04/21 22:25

    すごくコンパクトなコードを有難う御座います。こんなに短く表現できるというのはすごいです。皆様のコードを見ていると、人それぞれ違うのだなって改めて気づかせられます。

    またご指摘有難う御座います。
    「200,000」 は、「200000」の間違えです。

    一人で悩んでいて進まなかったのですが、これでJSONの加工に着手出来そうです。
    大変感謝しております。有難う御座います。

    キャンセル

+1

1.json, 2,json, 1.rb を示します。(ruby のコードは冗長になってますが、素直に書いてみています)
1.json
{"marker":[{"lat":41.772596,"lng":140.725261,"name":"函館朝市"},{"lat":41.796864,"lng":140.756965,"name":"五稜郭"},{"lat":41.772912,"lng":140.816231,"name":"函館空港"}]}
2.json
{"hokkaido":[{"name":"函館朝市"},{"ken":"北海道"},{"zinkou":200000}]}
1.rb
# coding: utf-8
require 'json'

json_files = ['1.json', '2.json'] # 入力ファイル
out_file = '3.json'  # 出力ファイル

infos = []
# json の読込み
json_files.each do |f|
  infos <<  open(f) do |io|
    JSON.load(io)
  end
end

# 2.json の構造を処理しやすいように変更する。
ary = []
infos[1].each do|key, mark|
  hash = {}
  # hash の配列を 1 つの hash に構成しなおす
  # [{"name":"函館朝市"}, {"ken":"北海道"}, {"zinkou":200000}]
  #   ==> {name => '', ken => '', zinkou => ''}
  mark.each do|m|
    m.each do|k, v|
      hash[k.to_sym] = v
    end
  end
  ary << hash
end
# p ary

ans = {}
# 1.json の name に対応する 2.json の ken を得る。
infos[0]['marker'].each do |mark|
  target_name = mark['name']
  ary.each do |a|
    ans[target_name] = a[:ken] if a[:name] == target_name
  end
end
p ans

# json 形式で保存
open(out_file, 'w') do |f|
  JSON.dump(ans, f)
end

実行すると画面には "{"函館朝市"=>"北海道"}" と表示されます。
3.json として、次の内容が出力されます。
{"函館朝市":"北海道"}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Ruby

    7368questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • JSON

    1120questions

    JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

  • Model

    80questions

    MVCモデルの一部であるModelはアプリケーションで扱うデータとその動作を管理するために扱います。