Łatwo jest wczytać plik CSV do tablicy za pomocą Ruby, ale nie mogę znaleźć dobrej dokumentacji na temat zapisywania tablicy w pliku CSV. Czy ktoś może mi powiedzieć, jak to zrobić?
Używam Ruby 1.9.2, jeśli to ma znaczenie.
Łatwo jest wczytać plik CSV do tablicy za pomocą Ruby, ale nie mogę znaleźć dobrej dokumentacji na temat zapisywania tablicy w pliku CSV. Czy ktoś może mi powiedzieć, jak to zrobić?
Używam Ruby 1.9.2, jeśli to ma znaczenie.
Odpowiedzi:
Do pliku:
require 'csv'
CSV.open("myfile.csv", "w") do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
Do ciągu:
require 'csv'
csv_string = CSV.generate do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
Oto aktualna dokumentacja dotycząca CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html
Mam tylko jedną linię.
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"
Wykonaj wszystkie powyższe czynności i zapisz w pliku csv w jednym wierszu.
File.open("ss.csv", "w") {|f| f.write(rows.inject([]) { |csv, row| csv << CSV.generate_line(row) }.join(""))}
UWAGA:
Myślę, że konwersja bazy danych aktywnych rekordów do csv byłaby czymś takim
CSV.open(fn, 'w') do |csv|
csv << Model.column_names
Model.where(query).each do |m|
csv << m.attributes.values
end
end
Hmm @tamouse, ta treść jest dla mnie nieco myląca bez czytania źródła csv, ale ogólnie, zakładając, że każdy skrót w twojej tablicy ma tę samą liczbę par k / v i że klucze są zawsze takie same, w tej samej kolejności (tj. jeśli twoje dane są uporządkowane), powinno to zrobić:
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
Jeśli twoje dane nie są uporządkowane, to oczywiście nie zadziała
inject
tutaj, naprawdę chcesz z niego korzystać map
. Ponadto nie musisz przekazywać pustego ciągu join
, ponieważ jest to ustawienie domyślne. Możesz więc zmniejszyć to jeszcze bardziej:rows.map(&CSV.method(:generate_line).join
CSV.generate(headers: hsh.first&.keys) { |csv| hsh.each { |e| csv << e } }
generuje równoważny CSV.
Jeśli ktoś jest zainteresowany, oto kilka linijek (i uwaga na temat utraty informacji o typie w 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
Uwaga: CSV traci wszystkie informacje o typie, możesz użyć JSON, aby zachować podstawowe informacje o typie, lub przejść do pełnego (ale łatwiejszego do edycji przez człowieka) YAML, aby zachować wszystkie informacje o typie - na przykład, jeśli potrzebujesz typu daty, który stałby się ciągi w CSV i JSON.
Opierając się na odpowiedzi @ boulder_ruby, właśnie tego szukam, zakładając, że us_eco
zawiera tabelę CSV z mojej treści.
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
Zaktualizowano treść na https://gist.github.com/tamouse/4647196
Sam sobie z tym walczę. Oto moje zdanie:
https://gist.github.com/2639448 :
require 'csv'
class CSV
def CSV.unparse array
CSV.generate do |csv|
array.each { |i| csv << i }
end
end
end
CSV.unparse [ %w(your array), %w(goes here) ]
[ %w(your array), %w(goes here) ]
nie będzie ładnie wyglądać. github.com/pry/pry/issues/568