É bastante fácil ler um arquivo CSV em uma matriz com Ruby, mas não consigo encontrar nenhuma boa documentação sobre como gravar uma matriz em um arquivo CSV. Alguém pode me dizer como fazer isso?
Estou usando o Ruby 1.9.2, se isso importa.
É bastante fácil ler um arquivo CSV em uma matriz com Ruby, mas não consigo encontrar nenhuma boa documentação sobre como gravar uma matriz em um arquivo CSV. Alguém pode me dizer como fazer isso?
Estou usando o Ruby 1.9.2, se isso importa.
Respostas:
Para um arquivo:
require 'csv'
CSV.open("myfile.csv", "w") do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
Para uma sequência:
require 'csv'
csv_string = CSV.generate do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
Aqui está a documentação atual em CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html
Eu tenho isso em apenas uma linha.
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"
Faça tudo o que precede e salve em um csv, em uma linha.
File.open("ss.csv", "w") {|f| f.write(rows.inject([]) { |csv, row| csv << CSV.generate_line(row) }.join(""))}
NOTA:
Para converter um banco de dados de registro ativo para CSV seria algo parecido com isto, eu acho
CSV.open(fn, 'w') do |csv|
csv << Model.column_names
Model.where(query).each do |m|
csv << m.attributes.values
end
end
Hmm @tamouse, essa essência é um pouco confusa para mim sem ler a fonte csv, mas genericamente, assumindo que cada hash em sua matriz tem o mesmo número de pares k / v e que as chaves são sempre as mesmas, na mesma ordem (por exemplo, se seus dados estiverem estruturados), isso deve fazer a ação:
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
Se seus dados não estiverem estruturados, isso obviamente não funcionará
inject
usando mal aqui, você realmente quer usar map
. Além disso, você não precisa passar uma string vazia para join
, pois esse é o padrão. Para que você possa encolher ainda mais isso:rows.map(&CSV.method(:generate_line).join
CSV.generate(headers: hsh.first&.keys) { |csv| hsh.each { |e| csv << e } }
gera um CSV equivalente.
Se alguém estiver interessado, aqui estão algumas orientações (e uma observação sobre a perda de informações de tipo no 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
Nota: O CSV perde todas as informações de tipo, você pode usar JSON para preservar informações básicas de tipo ou ir para o YAML detalhado (mas mais facilmente editável por humanos) para preservar todas as informações de tipo - por exemplo, se você precisar de um tipo de data, que se tornaria strings em CSV e JSON.
Com base na resposta de @ boulder_ruby, é isso que estou procurando, supondo que us_eco
contenha a tabela CSV a partir da minha essência.
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
Atualizado o gist em https://gist.github.com/tamouse/4647196
Lutando com isso sozinho. Esta é a minha opinião:
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) ]
não ficará bonito. github.com/pry/pry/issues/568