计算哈希值的排名并将其插入 Ruby 中的 CSV 文件

Calculate rank of hash value and insert it into a CSV file in Ruby

我有一个散列

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 保留了哈希的插入顺序,在这种情况下,哈希 h1 已经处于正确的顺序。但是,如果数据来自 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 之前。

我假设 key-value 对 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 的 key-value 对保证按值递减的顺序排列(如示例所示),则无需计算数组 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