2011-01-27 29 views
134

Thật dễ dàng để đọc một tệp CSV thành một mảng với Ruby nhưng tôi không thể tìm thấy bất kỳ tài liệu hướng dẫn tốt 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?Mảng đầu ra cho CSV trong Ruby

Tôi đang sử dụng Ruby 1.9.2 nếu có vấn đề.

+3

Câu trả lời bạn có thật tuyệt, nhưng hãy để tôi yêu cầu bạn không 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 tách bằng tab sẽ dễ dàng hơn nhiều để xử lý vì chúng không liên quan đến trích dẫn và thoát khỏi quá nhiều và như vậy. Nếu bạn phải sử dụng CSV, tất nhiên, đó là các điểm ngắt. –

+7

@Bill, mô-đun CSV xử lý gọn gàng các tệp được phân cách bằng tab cũng như 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 tốt. – tamouse

+1

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

Trả lời

246

Đối với một tập tin:

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

Để 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 hướng dẫn hiện hành về CSV: http://ruby-doc.org/stdlib/libdoc/csv/rdoc/index.html

+0

"w" là gì? –

+1

@David đó là chế độ tệp. "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 http://www.ruby-doc.org/core-1.9.3/IO.html để biết danh sách các chế độ tệp hợp lệ trong Ruby. –

+12

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 lại không ghi đè tệp csv trước đó, hãy sử dụng tùy chọn "ab". –

2

Đấu tranh với điều này bản thân mình. Đây là quan điểm 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) ] 
+0

Btw, hãy cẩn thận với các mảng đa chiều trong pry trên JRuby. '[% w (mảng của bạn),% w (vào đây)]' sẽ không đẹp. https://github.com/pry/pry/issues/568 –

27

Tôi đã có này xuống chỉ còn 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" 

Có phải tất cả những điều trên tiết kiệm đến 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(""))} 

LƯU Ý:

Để chuyển đổi một cơ sở dữ liệu ghi lại hoạt động để 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 đó là hơi khó hiểu với tôi không đọc nguồn csv, nhưng nói chung, giả sử mỗi băm trong mảng của bạn có cùng số cặp k/v & rằng các khóa luôn giống nhau, theo thứ tự giống nhau (ví dụ: dữ liệu của bạn có cấu trúc), điều này sẽ làm các 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 này rõ ràng sẽ không làm việc

+0

Tôi đã lấy 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 tạo ra một Array of Hashes dưới dạng CSV (thực sự được phân cách bằng tab). Làm thế nào để? https://gist.github.com/4647196 – tamouse

+0

hmm ... mà gist hơi đục, nhưng được đưa ra một mảng băm, tất cả đều có cùng số cặp k/v và cùng một khóa, theo cùng thứ tự .. –

+0

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

7

xây dựng trên @ boulder_ruby của câu trả lời, đây là những gì tôi đang tìm kiếm , giả sử us_eco 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 các ý chính tại https://gist.github.com/tamouse/4647196

13

Nếu có ai quan tâm, đây là một số một lớp lót (và một ghi chú trên mất thông tin gõ vào 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 kiểu, bạn có thể sử dụng JSON để lưu giữ thông tin kiểu cơ bản, hoặc đi đến tiết kiệm (nhưng dễ dàng hơn) có thể chỉnh sửa YAML để bảo toàn tất cả thông tin kiểu - ví dụ, nếu bạn cần loại ngày, sẽ trở thành chuỗi trong CSV & JSON.

10

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

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

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

require "csv" 
File.write("ss.csv", rows.map(&:to_csv).join) 
Các vấn đề liên quan