我有一个哈希
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编写程序。
您可以使用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
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 之前。
我假设 的键值对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