Mảng đầu ra cho CSV trong Ruby


185

Thật dễ dàng để đọc tệp CSV thành một mảng bằng Ruby nhưng tôi không thể tìm thấy bất kỳ tài liệu hay nào về cách viết một mảng vào tệp CSV. Bất cứ ai có thể cho tôi biết làm thế nào để làm điều này?

Tôi đang sử dụng Ruby 1.9.2 nếu điều đó quan trọng.


3
Câu trả lời bạn có là rất tốt, nhưng hãy để tôi khuyên bạn không nên sử dụng CSV. Nếu bạn không có các tab trong dữ liệu của mình, các tệp được phân định bằng tab sẽ dễ xử lý hơn vì chúng không liên quan đến việc trích dẫn và thoát quá nhiều thứ quái dị. Nếu bạn phải sử dụng CSV, tất nhiên, đó là giờ nghỉ.
Bill Dueber

8
@Bill, mô-đun CSV xử lý gọn gàng các tệp được phân định bằng tab cũng như các tệp csv thực tế. Tùy chọn: col_sep cho phép bạn chỉ định dấu tách cột là "\ t" và tất cả đều ổn.
tamouse

1
đây là thông tin thêm về CSV docs.ruby-lang.org/en/2.1.0/CSV.html
veeresh yh

Sử dụng các tệp .tab với mô-đun này là điều tôi đang làm, bởi vì việc mở nó trong Excel một cách tình cờ sẽ làm rối tung mã hóa
MrVocellect

Câu trả lời:


326

Để một tập tin:

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

Đến một chuỗi:

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

Đây là tài liệu hiện tại trên CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html


1
@David là chế độ tập tin. "W" có nghĩa là ghi vào một tập tin. Nếu bạn không chỉ định điều này, nó sẽ mặc định là "rb" (chế độ nhị phân chỉ đọc) và bạn sẽ gặp lỗi khi cố gắng thêm vào tệp csv của mình. Xem ruby-doc.org/core-1.9.3/IO.html để biết danh sách các chế độ tệp hợp lệ trong Ruby.
Dylan Markow

15
Gotcha. Và đối với người dùng trong tương lai, nếu bạn muốn mỗi lần lặp không ghi đè lên tệp csv trước đó, hãy sử dụng tùy chọn "ab".
boulder_ruby

1
Xem câu trả lời này cho các chế độ IO của Ruby File: stackoverflow.com/a/3682374/224707
Nick

37

Tôi đã nhận được điều này xuống chỉ một dòng.

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" 

Thực hiện tất cả các điều trên lưu vào một csv, trong một dòng.

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

GHI CHÚ:

Để chuyển đổi một cơ sở dữ liệu hồ sơ hoạt động sang csv sẽ là một cái gì đó như thế này tôi nghĩ

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

Hmm @tamouse, ý chính đó hơi khó hiểu với tôi khi không đọc nguồn csv, nhưng nói chung, giả sử mỗi hàm băm trong mảng của bạn có cùng số cặp k / v và các khóa luôn giống nhau, theo cùng một thứ tự (nghĩa là nếu dữ liệu của bạn được cấu trúc), điều này sẽ thực hiện hành động:

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

Nếu dữ liệu của bạn không có cấu trúc, điều này rõ ràng sẽ không hoạt động


Tôi đã lấy một tệp CSV bằng CSV.table, đã thực hiện một số thao tác, loại bỏ một số cột và bây giờ tôi muốn lưu lại Mảng kết quả băm ra dưới dạng CSV (thực sự được phân định bằng tab). Làm thế nào để? gist.github.com/4647196
tamouse

hmm ... ý chính đó hơi mờ, nhưng được đưa ra một loạt các giá trị băm, tất cả đều có cùng số cặp k / v và cùng khóa, theo cùng một thứ tự ...
boulder_ruby

Cảm ơn, @boulder_ruby. Điều đó sẽ làm việc. Dữ liệu là một bảng điều tra dân số và ý chính đó khá mờ khi nhìn lại nó. :) Về cơ bản, nó trích xuất một số cột nhất định từ bảng điều tra dân số ban đầu thành một tập hợp con.
tamouse

3
Bạn đang sử dụng sai injectở đây, bạn thực sự muốn sử dụng map. Ngoài ra, bạn không cần phải truyền một chuỗi trống tới join, vì đây là mặc định. Vì vậy, bạn có thể thu nhỏ nó hơn nữa về điều này:rows.map(&CSV.method(:generate_line).join
iGEL

1
Ví dụ thứ hai của bạn quá phức tạp, vì thư viện CSV khá mạnh. CSV.generate(headers: hsh.first&.keys) { |csv| hsh.each { |e| csv << e } }tạo một CSV tương đương.
Amadan

28

Nếu bạn có một mảng các mảng dữ liệu:

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

Sau đó, bạn có thể viết nó vào một tệp với những điều sau đây, mà tôi nghĩ đơn giản hơn nhiều:

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

20

Nếu bất cứ ai quan tâm, đây là một số lớp lót (và một lưu ý về việc mất thông tin loại trong 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

Lưu ý: CSV mất tất cả thông tin loại, bạn có thể sử dụng JSON để lưu giữ thông tin loại cơ bản hoặc đi tới verbose (nhưng dễ chỉnh sửa hơn con người) YAML để lưu giữ tất cả thông tin loại - ví dụ: nếu bạn cần loại ngày, sẽ trở thành chuỗi trong CSV & JSON.


9

Dựa trên câu trả lời của @ boulder_ruby, đây là những gì tôi đang tìm kiếm, giả sử us_ecocó chứa bảng CSV như từ ý chính của tôi.

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

Đã cập nhật ý chính tại https://gist.github.com/tamouse/4647196


2

Đấu tranh với bản thân mình Đây là mất của tôi:

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) ]

Btw, hãy cẩn thận với các mảng đa chiều trong pry trên JRuby. [ %w(your array), %w(goes here) ]trông sẽ không đẹp github.com/pry/pry/issues/568
Felix Rabe
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.