提供此CSV文件:
date,name,st,code,num
2020-03-25,AB,53,2585,130
2020-03-26,AB,53,3208,151
2020-03-26,BA,35,136,1
2020-03-27,BA,35,191,1
我想使用给定的数据创建以下哈希:
{:AB=>[["2020-03-25", "2585"], ["2020-03-26", "3208"]], :BA=>[["2020-03-26", "136"], ["2020-03-27", "191"]]}
我尝试过:
require 'csv'
h=Hash.new([])
CSV.foreach('file.csv', headers: true) do |row|
h[row['st']] << [[row['date'], row['code']]
end
但是我得到的只是一个空哈希h
。
首先创建CSV文件。
str =<<~_
date,name,st,code,num
2020-03-25,AB,53,2585,130
2020-03-26,AB,53,3208,151
2020-03-26,BA,35,136,1
2020-03-27,BA,35,191,1
_
FName = 't'
File.write(FName, str)
#=> 120
现在,我们可以简单地使用CSV::foreach逐行读取文件,它不带任何块就返回一个枚举数,并随着我们的前进构建哈希。
require 'csv'
CSV.foreach(FName, headers: true).
with_object(Hash.new { |h,k| h[k] = [] }) do |row,h|
h[row['name'].to_sym] << [row['date'], row['code']]
end
#=> {:AB=>[["2020-03-25", "2585"], ["2020-03-26", "3208"]],
# :BA=>[["2020-03-26", "136"], ["2020-03-27", "191"]]}
我已将Hash::new方法与一个块一起使用以创建哈希h
,以便如果h
没有键k
,则h[k]
会导致h[k] #=> []
。这样,当h[k] << 123
没有键h
时,k
会产生h[k] #=> [123]
。
或者,可以写:
CSV.foreach(FName, headers: true).with_object({}) do |row,h|
(h[row['name'].to_sym] ||= []) << [row['date'], row['code']]
end
一个人也可以使用converter将name
的值转换为符号,但有些人可能会认为这是过分的:
CSV.foreach(FName, headers: true,
converters: [->(v) { v.match?(/\p{Alpha}+/) ? v.to_sym : v }] ).
with_object(Hash.new { |h,k| h[k] = [] }) do |row,h|
h[row['name']] << [row['date'], row['code']]
end
无需读取CSV文件作为文本文件或其他内容;您可以按预期使用CSV并解决眼前的实际问题!
所以这里有3个问题:
h = Hash.new([])
改用它:h = Hash.new {|h, k| h[k] = [] }
参见:https://stackoverflow.com/a/28916684/5641227 @jack注释!headers: true
,因为第一行在您的情况下是标题行。h[row['name']] = h[row['name']] << [row['date'], row['code']]
这里,这对您有用:
require 'csv'
h = Hash.new { |h, k| h[k] = [] }
CSV.foreach('file.csv', headers: true) do |row|
h[row['name']] = h[row['name']] << [row['date'], row['code']]
end
#=> {"AB"=>[["2020-03-25", "2585"], ["2020-03-26", "3208"]], "BA"=>[["2020-03-26", "136"], ["2020-03-27", "191"]]}