É 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?
A resposta que você tem é ótima, mas permita-lhe que você não use CSV. Se você não possui guias em seus dados, os arquivos delimitados por tabulações são muito mais fáceis de lidar, porque eles não envolvem tantas citações e escapações assustadoras e tal. Se você deve usar o CSV, é claro, são as quebras.
Bill Dueber
8
@ Bill, o módulo CSV manipula ordenadamente arquivos delimitados por tabulações, bem como arquivos csv reais. A opção: col_sep permite especificar o separador de colunas como "\ t" e está tudo bem.
@ David é o modo de arquivo. "w" significa gravar em um arquivo. Se você não especificar isso, o padrão será "rb" (modo binário somente leitura) e você receberá um erro ao tentar adicionar ao seu arquivo csv. Veja ruby-doc.org/core-1.9.3/IO.html para obter uma lista dos modos de arquivo válidos no Ruby.
Dylan Markow
15
Peguei vocês. E para usuários futuros, se você quiser que cada iteração não substitua o arquivo csv anterior, use a opção "ab".
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 +=1if rowid ==1
csv << hsh.keys# adding header row (column labels)else
csv << hsh.values
end# of if/else inside hshend# of hsh's (rows)end# of csv open
Se seus dados não estiverem estruturados, isso obviamente não funcionará
Peguei um arquivo CSV usando CSV.table, fiz algumas manipulações, me livrei de algumas colunas e agora quero colocar em spool o Array of Hashes resultante novamente como CSV (realmente delimitado por tabulações). Como? gist.github.com/4647196
tamouse
hmm ... que essência é um pouco opaco, mas dado um array de hashes, todos com o mesmo número de k / v pares e as mesmas chaves, na mesma ordem ...
boulder_ruby
Obrigado, @boulder_ruby. Isso vai funcionar. Os dados são uma tabela do censo, e essa essência é bastante opaca olhando para trás. :) Basicamente, extrai determinadas colunas da tabela de censo original em um subconjunto.
tamouse
3
Você está injectusando 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
iGEL
1
Seu segundo exemplo é muito complicado, pois a biblioteca CSV é bastante poderosa. 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.
Respostas:
Para um arquivo:
Para uma sequência:
Aqui está a documentação atual em CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html
fonte
Eu tenho isso em apenas uma linha.
Faça tudo o que precede e salve em um csv, em uma linha.
NOTA:
Para converter um banco de dados de registro ativo para CSV seria algo parecido com isto, eu acho
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:
Se seus dados não estiverem estruturados, isso obviamente não funcionará
fonte
inject
usando mal aqui, você realmente quer usarmap
. Além disso, você não precisa passar uma string vazia parajoin
, 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 você tiver uma matriz de matrizes de dados:
Então você pode escrever isso em um arquivo com o seguinte, que eu acho que é muito mais simples:
fonte
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):
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.
fonte
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.Atualizado o gist em https://gist.github.com/tamouse/4647196
fonte
Lutando com isso sozinho. Esta é a minha opinião:
https://gist.github.com/2639448 :
fonte
[ %w(your array), %w(goes here) ]
não ficará bonito. github.com/pry/pry/issues/568