从CSV导入Ruby数组,第一个字段作为散列键,然后查找给定标题行的字段值

Mar*_*cos 27 ruby csv arrays hash stocks

也许有人可以帮助我.

从像这样的CSV文件开始:

Ticker,"Price","Market Cap"
ZUMZ,30.00,933.90
XTEX,16.02,811.57
AAC,9.83,80.02
Run Code Online (Sandbox Code Playgroud)

我设法把它们读成一个数组:

require 'csv'
tickers = CSV.read("stocks.csv", {:headers => true, :return_headers => true, :header_converters => :symbol, :converters => :all} )
Run Code Online (Sandbox Code Playgroud)

要验证数据,这有效:

puts tickers[1][:ticker]
ZUMZ
Run Code Online (Sandbox Code Playgroud)

但是,这不是:

puts tickers[:ticker => "XTEX"][:price]
Run Code Online (Sandbox Code Playgroud)

如何使用自动收录器字段作为唯一键将此数组转换为哈希值,以便我可以轻松地按照输入的第1行中的定义查找任何其他字段?处理更多的列和行.

非常感激!

Mic*_*ohl 33

像这样(它也适用于其他CSV,而不仅仅是你指定的那个):

require 'csv'

tickers = {}

CSV.foreach("stocks.csv", :headers => true, :header_converters => :symbol, :converters => :all) do |row|
  tickers[row.fields[0]] = Hash[row.headers[1..-1].zip(row.fields[1..-1])]
end
Run Code Online (Sandbox Code Playgroud)

结果:

{"ZUMZ"=>{:price=>30.0, :market_cap=>933.9}, "XTEX"=>{:price=>16.02, :market_cap=>811.57}, "AAC"=>{:price=>9.83, :market_cap=>80.02}}
Run Code Online (Sandbox Code Playgroud)

您可以像这样访问此数据结构中的元素:

puts tickers["XTEX"][:price] #=> 16.02
Run Code Online (Sandbox Code Playgroud)

编辑(根据评论):为了选择元素,你可以做类似的事情

 tickers.select { |ticker, vals| vals[:price] > 10.0 }
Run Code Online (Sandbox Code Playgroud)

  • 如果这个答案对你有所帮助,请upvote和/或接受(投票箭头下面的小刻度标记),这就是StackOverflow礼仪.我将更新我的答案以解决过滤问题:-) (2认同)

Mr.*_*ael 5

CSV.read(file_path, headers:true, header_converters: :symbol, converters: :all).collect do |row|
  Hash[row.collect { |c,r| [c,r] }]
end
Run Code Online (Sandbox Code Playgroud)


Mar*_*cos 0

为了获得两全其美的效果(从大文件中快速读取以及本机 Ruby CSV 对象的好处),我的代码后来演变成了这种方法:

$stock="XTEX"
csv_data = CSV.parse IO.read(%`|sed -n "1p; /^#{$stock},/p" stocks.csv`), {:headers => true, :return_headers => false, :header_converters => :symbol, :converters => :all}

# Now the 1-row CSV object is ready for use, eg:
$company = csv_data[:company][0]
$volatility_month = csv_data[:volatility_month][0].to_f
$sector = csv_data[:sector][0]
$industry = csv_data[:industry][0]
$rsi14d = csv_data[:relative_strength_index_14][0].to_f
Run Code Online (Sandbox Code Playgroud)

这更接近我原来的方法,但只读取一条记录加上包含标题的输入 csv 文件的第 1 行。内联sed指令可以解决这个问题——而且整个过程非常即时。这比一个更好,因为现在我可以从 Ruby 访问所有字段,并且可以关联地访问,不再像awk.