3

Hash to csv

hash :

{
"employee" => [
  {
    "name" => "Claude",
    "lastname"=> "David",
    "profile" => [
       "age" => "43",
       "jobs" => [
         {
           "name" => "Ingeneer",
           "year" => "5"
         }
       ],
       "graduate" => [
          {
             "place" => "Oxford",
             "year" => "1990"
          },
       ],
       "kids" => [
         {
           "name" => "Viktor",
           "age" => "18",
         }
    ]
  }
}]

this is an example of an hash I would work on. So, as you can see, there is many level of array in it.

My question is, how do I put it properly in a CSV file?

I tried this :

column_names = hash['employee'].first.keys
s=CSV.generate do |csv|
   csv << column_names
   hash['scrap'].each do |x|
     csv << x.values
   end
end
File.write('myCSV.csv', s)

but I only get name, lastname and profile as keys, when I would catch all of them (age, jobs, name , year, graduate, place...).

Beside, how can I associate one value per case? Because I actually have all employee[x] which take a cell alone. Is there any parameters I have missed?

Ps: This could be the following of this post

Community
  • 1
  • 1
Sokrah
  • 105
  • 1
  • 1
  • 11
  • 1
    My recommendation is not to start with that hash. Create the CSV from the same source the hash was created from. – Mark Thomas Jul 01 '15 at 14:30

3 Answers3

1

If you want to convert the hash to a CSV file or record, you'll need to get a 'flat' representation of your keys and values. Something like the following:

h = {
 a: 1,
 b: {
  c: 3,
  d: 4,
  e: {
    f: 5
  },
  g: 6
 } 
}

def flat_keys(h)
  h.keys.reject{|k| h[k].is_a?(Hash)} + h.values.select{|v| v.is_a?(Hash)}.flat_map{|v| flat_keys(v)}
end

flat_keys(h)
# [:a, :c, :d, :g, :f]

def flat_values(h)
  h.values.flat_map{|v| v.is_a?(Hash) ? flat_values(v) : v}
end

flat_values(h)
# [1, 3, 4, 5, 6]

Then you can apply that to create a CSV output.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Joshua
  • 2,079
  • 20
  • 29
1

A valid CSV output has a fixed number of columns, your hash has a variable number of values. The keys jobs, graduate and kids could all have multiple values.

If your only goal is to make a CSV output that can be read in Excel for example, you could enumerate your Hash, take the maximum number of key/value pairs per key, total it and then write your CSV output, filling the blank values with "".

There are plenty of examples here on Stack Overflow, search for "deep hash" to start with.

Your result would have a different number of columns with each Hash you provide it.

That's too much work if you ask me. If you just want to present a readable result, your best and easiest option is to convert the Hash to YAML which is created for readability:

require 'yaml'
hash = {.....}
puts hash.to_yaml

employee:
- name: Claude
  lastname: David
  profile:
  - age: '43'
    jobs:
    - name: Ingeneer
      year: '5'
    graduate:
    - place: Oxford
      year: '1990'
    kids:
    - name: Viktor
      age: '18'
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
peter
  • 41,770
  • 5
  • 64
  • 108
  • _A valid csv has a fixed number of columns, your hash has a variable number of values_ . Well, indeed I was about to use your method with empty cells (""). **deep hash** : that's tottaly my case, have no idea of this nickname, that's will help me a lot. For the yaml option, that's a good tip! Even if i'll try to figure out how to solve my problem before, that's definitvly a way I will explore. Thank you. – Sokrah Jul 01 '15 at 14:40
0

It depends on how those fields are represented in the database.

For example, your jobs has a hash with name key and your kids also has a hash with name key, so you can't just 'flatten' them, because keys have to be unique.

jobs is probably another model (database table), so you probably would have to (depending on the database) write it separately, including things like the id of the related object and so on.

Are you sure you're not in over your head? Judging from your last question and because you seem to treat csv's as simple key-values pair omitting all the database representation and relations.

Piotr Kruczek
  • 2,384
  • 11
  • 18
  • I would agree with you if I actually wanted to export it to a database. But this is not my goal here, I am practicing with ruby. And now on, I'm just looking to match hash and csv ! – Sokrah Jul 01 '15 at 13:52
  • To make my point clearer, all I want here would be to export a csv file that can be readable by a third party that has no knowledge with computer. And since i'm not in business yet, I do not own an interface database/user. I'm just looking for explore all that ruby could offer to me. – Sokrah Jul 01 '15 at 13:57