루비에서 CSV로 출력 배열


185

Ruby를 사용하여 CSV 파일을 배열로 읽는 것은 쉽지만 CSV 파일로 배열을 쓰는 방법에 대한 좋은 문서는 찾을 수 없습니다. 누구 든지이 작업을 수행하는 방법을 말해 줄 수 있습니까?

중요한 경우 Ruby 1.9.2를 사용하고 있습니다.


3
당신이 가진 대답은 훌륭하지만 CSV를 사용하지 말 것을 촉구합니다. 데이터에 탭이 없으면 탭으로 구분 된 파일은 너무 많은 인용 및 이스케이프 등을 포함하지 않기 때문에 처리하기가 훨씬 쉽습니다. 물론 CSV를 사용해야하는 경우에는 휴식 시간입니다.
Bill Dueber

8
@Bill, CSV 모듈은 탭으로 구분 된 파일과 실제 CSV 파일을 깔끔하게 처리합니다. : col_sep 옵션을 사용하면 열 구분 기호를 "\ t"로 지정할 수 있습니다.
tamouse


Excel에서이 파일을 우연히 열면 인코딩이 엉망이되기 때문에이 모듈과 함께 .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 을 참조하십시오 .
Dylan Markow

15
알았어 이후 사용자를 위해 각 반복에서 이전 csv 파일을 덮어 쓰지 않으려면 "ab"옵션을 사용하십시오.
boulder_ruby

1
Ruby 파일 IO 모드에 대해서는이 답변을 참조하십시오 : stackoverflow.com/a/3682374/224707
Nick

38

나는 이것을 한 줄로 줄였습니다.

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" 

위의 모든 수행 한 줄에하는 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, 그 요지는 CSS 소스를 읽지 않고 나에게 다소 혼란 스럽지만 일반적으로 배열의 각 해시가 같은 수의 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

감사합니다, @boulder_ruby. 작동합니다. 데이터는 센서스 테이블이며, 요점은 다시 불투명하게 보입니다. :) 기본적으로 원래 인구 조사 테이블에서 특정 열을 하위 집합으로 추출합니다.
tamouse

3
inject여기서 잘못 사용하고 있습니다 map. 정말로 사용하고 싶습니다 . 또한 빈 문자열을 join기본값으로 전달할 필요가 없습니다 . 따라서 다음과 같이 더 rows.map(&CSV.method(:generate_line).join
줄일 수 있습니다

1
CSV 라이브러리는 매우 강력하므로 두 번째 예제는 너무 복잡합니다. CSV.generate(headers: hsh.first&.keys) { |csv| hsh.each { |e| csv << e } }동등한 CSV를 생성합니다.
Amadan

28

데이터 배열이있는 경우 :

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

그런 다음 다음을 사용하여 파일에 쓸 수 있습니다.

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

20

관심있는 사람은 다음과 같습니다. 몇 가지 라이너 (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.