如何将CSV数据读入哈希[重复项]

问题描述 投票:0回答:2

提供此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

ruby csv hash
2个回答
1
投票

首先创建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  

一个人也可以使用convertername的值转换为符号,但有些人可能会认为这是过分的:

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  

1
投票

无需读取CSV文件作为文本文件或其他内容;您可以按预期使用CSV并解决眼前的实际问题!

所以这里有3个问题:

  1. 这将不起作用h = Hash.new([])改用它:h = Hash.new {|h, k| h[k] = [] }参见:https://stackoverflow.com/a/28916684/5641227 @jack注释!
  2. 您需要headers: true,因为第一行在您的情况下是标题行。
  3. 您只推送到不会做的values数组!您需要像这样覆盖: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"]]}
© www.soinside.com 2019 - 2024. All rights reserved.