【问题标题】:Create a Hash from a CSV-like file从类似 CSV 的文件创建哈希
【发布时间】:2012-02-23 18:31:48
【问题描述】:

我有一个列出商品编号、产品和价格的产品文件。我想读取此文件并将其初始化为哈希,其中项目 # 是键,产品和价格是值。这是我的文件

199, Shoes, 59.99
211, Shirts, 19.99
245, Hats, 25.99
689, Coats, 99.99
712, Beanies, 6.99

我希望它看起来像这样。

products = {
  199 =>['Shoes', 59.99],
  211 =>['Shirts', 19.99],
  245 =>['Hats', 25.99],
  689 => ['Coats', 99.99],
  712 => ['Beanies', 6.99]
}

这是我能想到的,但并不是它真正想要的。

products_file = File.open("files.txt")
products_hash = []
while ! products_file.eof?
  product_hash = products_file.gets.chomp
  print product_hash.split(', ')
end

这是我想出的输出:

["199", "Shoes", "59.99"]
["211", "Shirts", "19.99"]
["245", "Hats", "25.99"]
["689", "Coats", "99.99"]
["712", "Beanies", "6.99"]

【问题讨论】:

    标签: ruby csv


    【解决方案1】:

    我将您的数据保存为名为 products.csv 的 CSV 文件并执行此操作:

    require 'csv'
    products = {}
    CSV.foreach("products.csv") do |line| 
      products[line[0].to_i] = [line[1].strip, line[2].to_f]
    end
    products
    #=> {199=>["Shoes", 59.99], 211=>["Shirts", 19.99], 245=>["Hats", 25.99], 689=>["Coats", 99.99], 712=>["Beanies", 6.99]}
    

    使用each_with_object 可以以更简洁的方式实现相同的结果,但它会一次将整个文件读入内存,如果文件很大,这可能不是一个好主意:

    require 'csv'
    products = CSV.read("products.csv").each_with_object({}) do |line, h|
      h[line[0].to_i] = [line[1].strip, line[2].to_f]
    end 
    

    还有一种更实用的方法,正如 Phrogz 最初建议的那样:

    require 'csv'
    products = Hash[ CSV.read('products.csv').map do |row|
      [ row[0].to_i, [row[1].strip,row[2].to_f] ]
    end ]
    

    【讨论】:

    • +1,很好的答案。我在这个话题上的记录很差,但是I advocate tap over each_with_object.
    • 我对@9​​87654329@ 的问题是我更喜欢在我想要转换的数据上调用方法,而不是在即将成为我结果的空集合上调用方法。但是,我认为对于这个用例intofill_with 将是一个不错的别名,可以稍微减轻我的担忧。就我个人而言,我一直使用inject,但发现新的 Rubyists 发现each_with_object 更容易理解。
    【解决方案2】:

    一种变体,使用 CSV 的转换器处理数据:

    require 'csv'
    products = {}
    CSV.foreach('products.csv', {col_sep: ', ', converters: :numeric}) do |row|
      products[row.shift] = row
    end
    p products
    #=> {199=>["Shoes", 59.99], 211=>["Shirts", 19.99], 245=>["Hats", 25.99], 689=>["Coats", 99.99], 712=>["Beanies", 6.99]}
    

    【讨论】:

    • +1,很好的解决方案。我最初的意图是让代码简单并展示一些 Ruby,但我认为你的也能做到这两点。
    猜你喜欢
    • 2017-04-12
    • 1970-01-01
    • 2014-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 2013-12-20
    • 2017-07-26
    相关资源
    最近更新 更多