Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Generate CSV String from Array #255

Closed
okuramasafumi opened this issue Aug 3, 2022 · 5 comments
Closed

Feature Request: Generate CSV String from Array #255

okuramasafumi opened this issue Aug 3, 2022 · 5 comments

Comments

@okuramasafumi
Copy link

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.

@kou
Copy link
Member

kou commented Aug 5, 2022

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.

@okuramasafumi
Copy link
Author

@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.

@kou
Copy link
Member

kou commented Aug 5, 2022

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

@ericgpks
Copy link
Contributor

ericgpks commented Aug 6, 2022

I would like to try this one !!

@kou
Copy link
Member

kou commented Aug 6, 2022

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 kou closed this as completed in ba7e77a Aug 23, 2022
peterzhu2118 pushed a commit to Shopify/ruby that referenced this issue Dec 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants