RubyでCSVに配列を出力


185

RubyでCSVファイルを配列に読み込むのは簡単ですが、配列をCSVファイルに書き込む方法に関する適切なドキュメントが見つかりません。誰でもこれを行う方法を教えてもらえますか?

必要であれば、Ruby 1.9.2を使用しています。


3
あなたの答えは素晴らしいですが、CSVを使用しないことをお勧めします。データにタブがない場合、タブ区切りのファイルは、引用やエスケープなどのフリークがそれほど必要ないため、処理がはるかに簡単です。もちろん、CSVを使用する必要がある場合、それは休憩です。
Bill Dueber、2011年

8
@ Bill、CSVモジュールはタブ区切りファイルと実際のcsvファイルを適切に処理します。:col_sepオプションを使用すると、列区切り文字を "\ t"として指定できます。
tamouse 2013年

1
CSVに関する詳細はこちら docs.ruby-lang.org/en/2.1.0/CSV.html
veeresh yh

事故によってExcelでこれを開くとエンコーディングまで混乱をothrwiseになるので、このモジュールで.TABファイルを使用すると...、私がやっているものです
MrVocabulary

回答:


326

ファイルへ:

require 'csv'
CSV.open("myfile.csv", "w") do |csv|
  csv << ["row", "of", "CSV", "data"]
  csv << ["another", "row"]
  # ...
end

文字列に:

require 'csv'
csv_string = CSV.generate do |csv|
  csv << ["row", "of", "CSV", "data"]
  csv << ["another", "row"]
  # ...
end

CSVに関する最新のドキュメントは次のとおりです。http//ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html


1
@Davidそれはファイルモードです。「w」はファイルへの書き込みを意味します。これを指定しない場合、デフォルトで "rb"(読み取り専用バイナリモード)になり、csvファイルに追加しようとするとエラーが発生します。Rubyで有効なファイルモードのリストについては、ruby-doc.org / core-1.9.3 / IO.htmlを参照してください。
ディランマルコウ2012

15
ゴッチャ。また、将来のユーザーのために、各反復で以前のcsvファイルを上書きしないようにする場合は、「ab」オプションを使用します。
boulder_ruby

1
RubyファイルIOモードについては、この回答を参照してください:stackoverflow.com/a/3682374/224707
Nick

38

これを1行にまとめました。

rows = [['a1', 'a2', 'a3'],['b1', 'b2', 'b3', 'b4'], ['c1', 'c2', 'c3'], ... ]
csv_str = rows.inject([]) { |csv, row|  csv << CSV.generate_line(row) }.join("")
#=> "a1,a2,a3\nb1,b2,b3\nc1,c2,c3\n" 

上記のすべてを行うと、 1行で、csvファイルに保存します。

File.open("ss.csv", "w") {|f| f.write(rows.inject([]) { |csv, row|  csv << CSV.generate_line(row) }.join(""))}

注意:

アクティブレコードデータベースをcsvに変換するには、次のようになります。

CSV.open(fn, 'w') do |csv|
  csv << Model.column_names
  Model.where(query).each do |m|
    csv << m.attributes.values
  end
end

うーん@tamouse、その要点はcsvソースを読み取らないと多少混乱しますが、一般的には、配列内の各ハッシュが同じ数のk / vペアを持ち、キーが常に同じ順序であると想定します(つまり、データが構造化されている場合)、これは実際に行われるはずです:

rowid = 0
CSV.open(fn, 'w') do |csv|
  hsh_ary.each do |hsh|
    rowid += 1
    if rowid == 1
      csv << hsh.keys# adding header row (column labels)
    else
      csv << hsh.values
    end# of if/else inside hsh
  end# of hsh's (rows)
end# of csv open

データが構造化されていない場合、これは明らかに機能しません


CSV.tableを使用してCSVファイルをプルし、いくつかの操作を実行し、いくつかの列を削除し、結果のハッシュの配列を再びCSV(実際にはタブ区切り)としてスプールします。方法?gist.github.com/4647196
tamouse

うーん...その要点はやや不透明ですが、ハッシュの配列が与えられ、すべて同じ数のk / vペアと同じキーが同じ順序で...
boulder_ruby 2013年

ありがとう、@ boulder_ruby。うまくいきます。データは国勢調査表であり、その要点はそれを振り返ってみるとかなり不透明です。:)基本的には、特定の列を元の国勢調査表からサブセットに抽出しています。
tamouse 2013年

3
あなたはinjectここで誤用しています、あなたは本当に使いたいですmap。また、joinこれはデフォルトなので、空の文字列をに渡す必要はありません。:あなたは、これにさらにそれを縮小することができるようにrows.map(&CSV.method(:generate_line).join
IGEL

1
CSVライブラリは非常に強力であるため、2番目の例は複雑すぎます。CSV.generate(headers: hsh.first&.keys) { |csv| hsh.each { |e| csv << e } }同等のCSVを生成します。
アマダン

28

データの配列の配列がある場合:

rows = [["a1", "a2", "a3"],["b1", "b2", "b3", "b4"], ["c1", "c2", "c3"]]

次に、これを次のようにファイルに書き込むことができます。

require "csv"
File.write("ss.csv", rows.map(&:to_csv).join)

20

興味のある方は、以下に1行(およびCSVでの型情報の喪失に関する注意)を示します。

require 'csv'

rows = [[1,2,3],[4,5]]                    # [[1, 2, 3], [4, 5]]

# To CSV string
csv = rows.map(&:to_csv).join             # "1,2,3\n4,5\n"

# ... and back, as String[][]
rows2 = csv.split("\n").map(&:parse_csv)  # [["1", "2", "3"], ["4", "5"]]

# File I/O:
filename = '/tmp/vsc.csv'

# Save to file -- answer to your question
IO.write(filename, rows.map(&:to_csv).join)

# Read from file
# rows3 = IO.read(filename).split("\n").map(&:parse_csv)
rows3 = CSV.read(filename)

rows3 == rows2   # true
rows3 == rows    # false

注:CSVはすべてのタイプ情報を失います。JSONを使用して基本的なタイプ情報を保持するか、詳細(ただし、より簡単に編集可能)YAMLに移動してすべてのタイプ情報を保持できます。たとえば、日付タイプが必要な場合、 CSVとJSONの文字列。


9

@boulder_rubyの答えに基づいて、これは私が探しているものですus_eco。私の趣旨のCSVテーブルが含まれていると想定しています。

CSV.open('outfile.txt','wb', col_sep: "\t") do |csvfile|
  csvfile << us_eco.first.keys
  us_eco.each do |row|
    csvfile << row.values
  end
end

https://gist.github.com/tamouse/4647196の要点を更新しました


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.