(Ruby) Как преобразовать вложенный хеш в CSV-файл - PullRequest
0 голосов
/ 11 марта 2019

Проблема:

У меня есть следующий хэш:

хэш = {1 => {: цена => "400",: brand => "Primark"}, 2 => {: price => "1000",: brand => "pull & bear"}, 3 => {: price => "1700",: brand => ""}, 4 => {: price => "500",: brand => "H & M"}, 5 => {: price => "500",: brand => "Mango"}}

и я хочу преобразовать его в CSV-файл.


Подход пока:

Мое ближайшее решение (вдохновлено) кажется, постоянно перезаписывается:

require 'csv'

(1..5).each do |id|
   column_names = hash[id].keys
   column_values = hash[id].values
   s=CSV.generate do |csv|
      csv << column_names
      csv << column_values
   end
   File.write('the_file.csv', s)
end

Текущий CSV-файл:

+---+------------+-------------+
|   |     A      |      B      |
+---+------------+-------------+
| 1 | price,brand|             |
| 2 | 500, Mango |             |
+---+------------+-------------+

Требуемый вывод CSV:

+---+------------+-------------+
|   |     A      |      B      |
+---+------------+-------------+
| 1 | price      | brand       |
| 2 | 400        | Primark     |
| 3 | 1000       | pull&bear   |
| 4 | 1700       |             |
| 5 | 500        | H&M         |
| 6 | 500        | mango       |
+---+------------+-------------+

Есть несколько вопросов наздесь, которые либо имеют дело с обратным (преобразование CSV во вложенный хэш), либо конвертируют только простые хеши в файлы CSV, но не с вложенными хэшами.Я довольно новичок в Ruby и пока не могу соединить точки здесь.Помощь будет принята с благодарностью!

Ответы [ 3 ]

4 голосов
/ 11 марта 2019

Я бы сделал что-то вроде этого:

require 'csv'

CSV.open('the_file.csv', 'w') do |csv|
  hash.each do |id, attributes|    
    csv << [id, *attributes.values_at(:price, :brand)]
  end
end
4 голосов
/ 11 марта 2019

Похоже, вас интересуют только значения вашего вложенного хэша. В этом случае вы можете просто сделать

titles = hash.values.map(&:keys).flatten.uniq
rows = hash.values.map { |data| data.values_at(*titles) }

s = CSV.generate do |csv|
  csv << titles
  rows.each do |row|
    csv << row
  end
end

(обновление)

Заголовки должны быть сведены в простой массив.

1 голос
/ 11 марта 2019

CSV формат по сути является массивом массивов. Каждый элемент основного массива представляет собой одну строку. Одна строка - это массив ячеек. Итак, что вы хотите в основном это что-то вроде этого:

[
  [:price, :brand],
  ["400", "Primark"],
  ["1000", "Pull&Bear"]
]

Вы можете достичь этого следующим образом:

headers = hash.values[0].keys # this will return [:price, :brand] and we'll use it as a header
data = hash.values.map(&:values)

csv_output = CSV.generate do |csv|
  csv << headers # we need headers only once, we don't need them in every row
  data.each do |single_row| # iterate over each row
    csv << single_row # add the row to csv file
  end
end
File.write('the_file.csv', csv_output)

В этом коде предполагается, что для каждой строки у вас будут все доступные данные (т. Е. В каждой строке будет указана цена и марка). Код выше, предоставленный переписанным пользователем, более гибок.

...