0

我有一个哈希

h1 = {"Cust1"=>500, "Cust4"=>400, "Cust2"=>100, "Cust3"=>100}

我想将此哈希插入到CSV文件中,并根据其值对键进行排名。

示例输出应如下所示

ID,Sales,Rank Cust1,500,1 Cust4,400,2 Cust2,100,3 Cust3,100,3

我必须用Ruby编写程序。

4

3 回答 3

2

您可以使用each_with_index哈希方法

arr = [['ID', 'Sales', 'Rank']]

h1.each_with_index do |(key, value), index|
  arr << [key, value, index + 1]
end

arr #[["ID", "Sales", "Rank"], ["Cust1", 500, 1], ["Cust4", 400, 2], ["Cust2", 100, 3], ["Cust3", 100, 4]]

CSV 代码

h1 = {"Cust1"=>500, "Cust4"=>400, "Cust2"=>100, "Cust3"=>100}
# You can skip following `sort_by` line if your hash is already ordered by desc value
h1 = h1.sort_by {|_k,v| v}.reverse.to_h
h2 = h1.group_by {|k,v| v }
require 'csv'
CSV.open("myfile.csv", "w") do |csv|
  csv << ['ID', 'Sales', 'Rank']
  h2.each_with_index do |(key, values), index|
    values.each do |value|
      csv << [value[0], key, index + 1]
    end
  end
end
于 2020-10-21T10:18:17.660 回答
0

OP要求计算排名;从 1.9 开始,Ruby 保留了 hash 的插入顺序,在这种情况下,hashh1的顺序已经正确。但是,如果数据来自 REST 调用或尚未按排序顺序排序,则上述解决方案将产生不正确的输出。要解决这个问题

require 'csv'

h1 = {"Cust1"=>500, "Cust2"=>100, "Cust4"=>400, "Cust3"=>100}

ranked_customers = h1.sort_by { |k, v| [-v, k] }.each_with_index { |e, i| e.push i + 1 }
ranked_customers.unshift %w[ID Sales Rank]

CSV { |csv_out| ranked_customers.each { |e| csv_out << e } }

生产

ID,Sales,Rank
Cust1,500,1
Cust4,400,2
Cust2,100,3
Cust3,100,4

Cust2 和 Cust3 都具有相同的销售价值,但 Cust2 按字母顺序排在 Cust3 之前。

于 2020-10-21T11:47:14.687 回答
0

我假设 的键值对h1不一定按值递减的顺序。

我们需要进行两次计算来构建 CSV 文件。

order = h1.sort_by { |_,v| -v }
  #=> [["Cust1", 500], ["Cust4", 400], ["Cust2", 100], ["Cust3", 100]]
nbr_ranks = order.map(&:last).uniq.size
  #=> 3

该文件可以按如下方式构建。

require 'csv'

CSV.open('t.csv', 'w') do |csv|
  csv << ['ID', 'Sales', 'Rank']
  last_val = order.first.last
  order.each do |name, val|
    unless val == last_val
      nbr_ranks -= 1
      last_val = val
    end
    csv << [name, val, nbr_ranks]
  end
end
puts File.read('t.csv')
ID,Sales,Rank
Cust1,500,1
Cust4,400,2
Cust2,100,3
Cust3,100,4

如果保证 的键值对按h1值递减的顺序(如示例中所示),则无需计算数组order

nbr_ranks = order.map(&:last).uniq.size
  #=> 3

CSV.open('t.csv', 'w') do |csv|
  csv << ['ID', 'Sales', 'Rank']
  last_val = h1[h1.keys.first]
  h1.each do |name, val|
    unless val == last_val
      nbr_ranks -= 1
      last_val = val
    end
    csv << [name, val, nbr_ranks]
  end
end

笔记:

last_val = h1[h1.keys.first]
  #=> 500
于 2020-10-21T19:33:48.297 回答