csv icon indicating copy to clipboard operation
csv copied to clipboard

Feature Request: Generate CSV String from Array

Open okuramasafumi opened this issue 3 years ago • 5 comments

Problem

When we have

array = [["foo", "bar"], [1, 2], [3, 4]]

one simple way to generate CSV String from this Array is:

header = array.shift
CSV::Table.new(array.map {|a| CSV::Row.new(header, a)}).to_csv # "foo,bar\n1,2\n3,4\n"

This works, but it's procedural and not intuitive.

It's often the case that it's easy to prepare data in form of Array, and difficult to prepare data in form of String, so it's good to have a way to directly convert Array into CSV String.

Solution

My suggestion is to add the method below:

CSV.generate_from_array(array) # "foo,bar\n1,2\n3,4\n"
CSV.generate_from_array(array, row_sep: "\r\n") # "foo,bar\r\n1,2\r\n3,4\r\n"

Advantages

  • It accepts the same options as generate to customize its behavior
  • It's short and intuitive

Disadvantages

  • A new method to remember

Implementtion

class CSV
  def self.generate_from_array(array, **options)
    CSV.generate(**options) do |csv|
      array.each do |row|
        csv << row
      end
    end
  end
end

This implementation works in my local environment. It's not optimized anyway.

okuramasafumi avatar Aug 03 '22 13:08 okuramasafumi

How about this?

diff --git a/lib/csv/core_ext/array.rb b/lib/csv/core_ext/array.rb
index 8beb06b..0180deb 100644
--- a/lib/csv/core_ext/array.rb
+++ b/lib/csv/core_ext/array.rb
@@ -4,6 +4,16 @@ class Array # :nodoc:
   #   ["CSV", "data"].to_csv
   #     #=> "CSV,data\n"
   def to_csv(**options)
-    CSV.generate_line(self, **options)
+    case first
+    when Array
+      output = +""
+      csv = CSV.new(output, **options)
+      each do |row|
+        csv << row
+      end
+      output
+    else
+      CSV.generate_line(self, **options)
+    end
   end
 end

If we use the suggested approach, I think that CSV.generate_lines(rows) is better.

kou avatar Aug 05 '22 05:08 kou

@kou I like CSV.generate_lines(rows) API. I think we can have CSV.generate_lines(rows) and Array#to_csv for nested array at the same time.

okuramasafumi avatar Aug 05 '22 15:08 okuramasafumi

OK. Do you want to work on this? Or does @ericgpks want to work on this?

kou avatar Aug 05 '22 15:08 kou

I would like to try this one !!

ericgpks avatar Aug 06 '22 03:08 ericgpks

OK! I'm waiting for your pull request for this! If you have any trouble, I can help you at https://gitter.im/red-data-tools/ja or pull request as usual.

kou avatar Aug 06 '22 13:08 kou