Вот как это сделать:
>>> mylist = ['a', 'b', 'c', 'd']
>>> [item for item in enumerate(mylist)]
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
В качестве альтернативы вы можете сделать:
>>> [(i, j) for i, j in enumerate(mylist)]
[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]
Причина, по которой вы получили сообщение об ошибке, заключалась в том, что вы отсутствовали () вокруг i
и j
, чтобы сделать его кортежем.
Я бы сделал что-то вроде этого:
require 'csv'
CSV.open('the_file.csv', 'w') do |csv|
hash.each do |id, attributes|
csv << [id, *attributes.values_at(:price, :brand)]
end
end
Похоже, вас интересуют только значения вашего вложенного хэша. В этом случае вы можете просто сделать
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
(обновить)
Заголовки должны быть сведены в простой массив.
Формат 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)
Этот код предполагает, что для каждой строки у вас будут все данные доступно (т.е. в каждой строке будет указана цена и марка). Код выше, предоставленный переписанным пользователем, более гибок.