web-dev-qa-db-ja.com

CSVからRuby配列にインポートし、最初のフィールドをハッシュキーとして使用して、ヘッダー行からフィールドの値を検索します

多分誰かが私を助けることができます。

次のようなCSVファイルから始めます:

Ticker,"Price","Market Cap"
ZUMZ,30.00,933.90
XTEX,16.02,811.57
AAC,9.83,80.02

私はそれらを配列に読み込むことができました:

require 'csv'
tickers = CSV.read("stocks.csv", {:headers => true, :return_headers => true, :header_converters => :symbol, :converters => :all} )

データを検証するために、これは機能します:

puts tickers[1][:ticker]
ZUMZ

しかし、これはしません:

puts tickers[:ticker => "XTEX"][:price]

ティッカーフィールドを一意のキーとして使用して、この配列をハッシュに変換し、入力の1行目で定義されている他のフィールドを連想的に簡単に検索できるようにするにはどうすればよいですか?より多くの列と行を扱う。

とても有難い!

27
Marcos

両方の長所(巨大なファイルから非常に高速に読み取り、ネイティブのRuby CSVオブジェクト)の利点)を得るには、コードがこのメソッドに進化しました。

$stock="XTEX"
csv_data = CSV.parse IO.read(%`|sed -n "1p; /^#{$stock},/p" stocks.csv`), {:headers => true, :return_headers => false, :header_converters => :symbol, :converters => :all}

# Now the 1-row CSV object is ready for use, eg:
$company = csv_data[:company][0]
$volatility_month = csv_data[:volatility_month][0].to_f
$sector = csv_data[:sector][0]
$industry = csv_data[:industry][0]
$rsi14d = csv_data[:relative_strength_index_14][0].to_f

これは私の元の方法に近いですが、ヘッダーを含む入力csvファイルの1つのレコードと1行目のみを読み取ります。インラインのsed命令がそれを処理します-そして、すべてが著しくインスタントです。これは last よりも優れています。これは、Rubyからすべてのフィールドにアクセスできるようになり、awkの場合のように列番号を気にする必要がなくなったためです。

0
Marcos

このように(指定したものだけでなく、他のCSVでも機能します):

require 'csv'

tickers = {}

CSV.foreach("stocks.csv", :headers => true, :header_converters => :symbol, :converters => :all) do |row|
  tickers[row.fields[0]] = Hash[row.headers[1..-1].Zip(row.fields[1..-1])]
end

結果:

{"ZUMZ"=>{:price=>30.0, :market_cap=>933.9}, "XTEX"=>{:price=>16.02, :market_cap=>811.57}, "AAC"=>{:price=>9.83, :market_cap=>80.02}}

次のように、このデータ構造の要素にアクセスできます。

puts tickers["XTEX"][:price] #=> 16.02

編集(コメントに従って):要素を選択するには、次のようなことができます

 tickers.select { |ticker, vals| vals[:price] > 10.0 }
33
Michael Kohl
CSV.read(file_path, headers:true, header_converters: :symbol, converters: :all).collect do |row|
  Hash[row.collect { |c,r| [c,r] }]
end

次の方法で要素にアクセスする場合は、Michael Kohlの回答に追加します。

puts tickers[:price]["XTEX"] #=> 16.02

次のコードスニペットを試すことができます。

CSV.foreach("Workbook1.csv", :headers => true, :header_converters => :symbol, :converters => :all) do |row|
    hash_row =  row.headers[1..-1].Zip( (Array.new(row.fields.length-1, row.fields[0]).Zip(row.fields[1..-1])) ).to_h
    hash_row.each{|key, value| tickers[key] ? tickers[key].merge!([value].to_h) : tickers[key] = [value].to_h}
end
1
clouddra

ワンライナーではありませんが、これは私にはより明確でした。

csv_headers = CSV.parse(STDIN.gets)
csv = CSV.new(STDIN)

kick_list = []
csv.each_with_index do |row, i|
  row_hash = {}
  row.each_with_index do |field, j|
    row_hash[csv_headers[0][j]] = field
  end
  kick_list << row_hash
end
0
Jesse Smith