Вычислить ранг хэш-значения и вставить его в файл CSV в 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.
3 ответа
Вы можете использовать
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
Я предполагаю, что пары "ключ-значение"
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
ОП просит вычислить ранг; начиная с 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 по алфавиту.