web-dev-qa-db-ja.com

各行の属性としてヘッダーフィールドを含むCSVファイルを解析する

CSVファイルを解析して、各行がオブジェクトのように扱われ、ヘッダー行がオブジェクトの属性の名前になるようにします。私はこれを書くことができましたが、すでにそこにあると確信しています。

ここに私のCSV入力があります:

"foo","bar","baz"
1,2,3
"blah",7,"blam"
4,5,6

コードは次のようになります。

CSV.open('my_file.csv','r') do |csv_obj|
  puts csv_obj.foo   #prints 1 the 1st time, "blah" 2nd time, etc
  puts csv.bar       #prints 2 the first time, 7 the 2nd time, etc
end

RubyのCSVモジュールを使用すると、インデックスでのみフィールドにアクセスできます。上記のコードはもう少し読みやすいと思います。何か案は?

63
Poul

Ruby 1.9以降を使用すると、インデックス付け可能なオブジェクトを取得できます。

CSV.foreach('my_file.csv', :headers => true) do |row|
  puts row['foo'] # prints 1 the 1st time, "blah" 2nd time, etc
  puts row['bar'] # prints 2 the first time, 7 the 2nd time, etc
end

ドット構文ではありませんが、数値インデックスよりも作業する方がはるかに優れています。

余談ですが、for Ruby 1.8.x FasterCSV は、上記の構文を使用するために必要なものです。

110
Peer Allan

Ruby 1.9を使用したシンボリック構文の例を次に示します。以下の例では、コードはRails dbディレクトリからdata.csvという名前のCSVファイルを読み取ります。

:headers => trueは、最初の行をデータ行ではなくヘッダーとして扱います。 :header_converters => :symbolizeパラメーターは、ヘッダー行の各セルをRubyシンボルに変換します。

CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row|
  puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}"
end

Ruby 1.8の場合:

require 'fastercsv'
CSV.foreach("#{Rails.root}/db/data.csv", {:headers => true, :header_converters => :symbol}) do |row|
  puts "#{row[:foo]},#{row[:bar]},#{row[:baz]}"
end

Poul(StackOverflow asker)が提供するCSVに基づくと、上記のサンプルコードの出力は次のようになります。

1,2,3
blah,7,blam
4,5,6

CSVファイルのヘッダーで使用される文字によっては、CSV(FasterCSV)が文字列ヘッダーをシンボルに変換する方法を確認するために、ヘッダーを出力する必要がある場合があります。 CSV.foreach内からヘッダーの配列を出力できます。

row.headers
36
scarver2

Ruby 2.3:でハッシュを取得するのは簡単

CSV.foreach('my_file.csv', headers: true, header_converters: :symbol) do |row|
  puts row.to_h[:foo]
  puts row.to_h[:bar]
end
5
Yarin

私は議論にかなり遅れましたが、数か月前に https://github.com/vicentereig/virgola で「CSV to object mapper」を開始しました。

CSVコンテンツを考えると、それらをFooBarオブジェクトの配列にマッピングするのは非常に簡単です:

"foo","bar","baz"
1,2,3
"blah",7,"blam"
4,5,6
require 'virgola'

class FooBar
  include Virgola

  attribute :foo
  attribute :bar
  attribute :baz
end

csv = <<CSV
"foo","bar","baz"
1,2,3
"blah",7,"blam"
4,5,6
CSV

foo_bars = FooBar.parse(csv).all
foo_bars.each { |foo_bar| puts foo_bar.foo, foo_bar.bar, foo_bar.baz }
2
Vicente Reig

私はいくつかの頻度でこの質問に答えたので

array_of_hashmaps = CSV.read("path/to/file.csv", headers: true)
puts array_of_hashmaps.first["foo"] # 1

これは、ファイル全体を丸lurみしたい場合の非ブロックバージョンです。

0
Narfanator