Array in CSV in Ruby ausgeben


185

Es ist einfach genug, eine CSV-Datei mit Ruby in ein Array einzulesen, aber ich kann keine gute Dokumentation zum Schreiben eines Arrays in eine CSV-Datei finden. Kann mir jemand sagen, wie das geht?

Ich verwende Ruby 1.9.2, wenn das wichtig ist.


3
Die Antwort, die Sie haben, ist großartig, aber ich möchte Sie dringend bitten, CSV nicht zu verwenden. Wenn Ihre Daten keine Registerkarten enthalten, sind tabulatorgetrennte Dateien viel einfacher zu handhaben, da sie nicht so viel verdammtes Zitieren und Entkommen und dergleichen beinhalten. Wenn Sie CSV verwenden müssen, sind dies natürlich die Pausen.
Bill Dueber

8
@Bill, das CSV-Modul verarbeitet ordentlich durch Tabulatoren getrennte Dateien sowie tatsächliche CSV-Dateien. Mit der Option: col_sep können Sie das Spaltentrennzeichen als "\ t" angeben, und alles ist in Ordnung.
Tamouse

1
Hier ist mehr Info über CSV docs.ruby-lang.org/en/2.1.0/CSV.html
veeresh yh

Die Verwendung von Tab-Dateien mit diesem Modul ist meine Aufgabe, da ein versehentliches Öffnen in Excel die Codierung anderweitig durcheinander bringen würde…
MrVocabulary

Antworten:


326

Zu einer Datei:

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

Zu einer Zeichenfolge:

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

Hier ist die aktuelle Dokumentation zu CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html


1
@ David ist es der Dateimodus. "w" bedeutet in eine Datei schreiben. Wenn Sie dies nicht angeben, wird standardmäßig "rb" (schreibgeschützter Binärmodus) verwendet, und beim Versuch, Ihrer CSV-Datei etwas hinzuzufügen, wird eine Fehlermeldung angezeigt. Eine Liste der gültigen Dateimodi in Ruby finden Sie unter ruby-doc.org/core-1.9.3/IO.html .
Dylan Markow

15
Erwischt. Wenn Sie für zukünftige Benutzer möchten, dass bei jeder Iteration die vorherige CSV-Datei nicht überschrieben wird, verwenden Sie die Option "ab".
boulder_ruby

1
Siehe diese Antwort für Ruby File IO-Modi: stackoverflow.com/a/3682374/224707
Nick

37

Ich habe das auf nur eine Zeile reduziert.

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" 

Führen Sie alle oben genannten Schritte aus und speichern Sie sie in einer Zeile in einem CSV.

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

HINWEIS:

Eine aktive Datensatzdatenbank in CSV zu konvertieren wäre ungefähr so, denke ich

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

Hmm @tamouse, das Wesentliche ist für mich etwas verwirrend, ohne die CSV-Quelle zu lesen, aber im Allgemeinen, vorausgesetzt, jeder Hash in Ihrem Array hat die gleiche Anzahl von k / v-Paaren und die Schlüssel sind immer gleich, in der gleichen Reihenfolge (dh Wenn Ihre Daten strukturiert sind, sollte dies die Tat tun:

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

Wenn Ihre Daten nicht strukturiert sind, funktioniert dies offensichtlich nicht


Ich habe eine CSV-Datei mit CSV.table eingezogen, einige Manipulationen vorgenommen, einige Spalten entfernt, und jetzt möchte ich das resultierende Array von Hashes wieder als CSV (wirklich tabulatorgetrennt) herausspulen. Wie man? gist.github.com/4647196
Tamouse

hmm ... das Wesentliche ist etwas undurchsichtig, aber mit einer Reihe von Hashes, alle mit der gleichen Anzahl von k / v-Paaren und den gleichen Schlüsseln, in der gleichen Reihenfolge ...
boulder_ruby

Danke, @boulder_ruby. Das wird funktionieren. Die Daten sind eine Zensus-Tabelle, und dieser Kern ist im Rückblick ziemlich undurchsichtig. :) Grundsätzlich werden bestimmte Spalten aus der ursprünglichen Zensus-Tabelle in eine Teilmenge extrahiert.
Tamouse

3
Sie missbrauchen injecthier, Sie wollen wirklich verwenden map. Außerdem müssen Sie keine leere Zeichenfolge übergeben join, da dies die Standardeinstellung ist. Sie könnten es also noch weiter verkleinern:rows.map(&CSV.method(:generate_line).join
iGEL

1
Ihr zweites Beispiel ist zu kompliziert, da die CSV-Bibliothek sehr leistungsfähig ist. CSV.generate(headers: hsh.first&.keys) { |csv| hsh.each { |e| csv << e } }generiert eine äquivalente CSV.
Amadan

28

Wenn Sie ein Array von Datenfeldern haben:

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

Dann können Sie dies in eine Datei mit den folgenden Angaben schreiben, was meiner Meinung nach viel einfacher ist:

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

20

Wenn jemand interessiert ist, hier einige Einzeiler (und ein Hinweis zum Verlust von Typinformationen in 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

Hinweis: CSV verliert alle Typinformationen. Sie können JSON verwenden, um grundlegende Typinformationen beizubehalten, oder YAML verwenden, um alle Typinformationen beizubehalten, z. B. wenn Sie einen Datumstyp benötigen Zeichenfolgen in CSV & JSON.


9

Aufbauend auf der Antwort von @ boulder_ruby ist dies das, wonach ich suche, vorausgesetzt, es us_ecoenthält die CSV-Tabelle aus meiner Sicht.

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

Das Wesentliche wurde unter https://gist.github.com/tamouse/4647196 aktualisiert


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.