Это один из способов создать желаемый хэш.Обратите внимание, что в arr1
«Джон» появляется три раза.
arr1 = ["David", "John", "Alex", "Sam", "Caleb",
"David", "John", "Alex", "John", "Sam"]
arr2 = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"]
prefixes =
arr1.each_with_object({}) do |s,h|
if h.key?(s)
prefix = "A-"
(h[s].size-1).times { prefix = prefix.next }
h[s] << prefix
else
h[s] = ['']
end
end
#=> {"David"=>["", "A-"], "John"=>["", "A-", "B-"],
# "Alex"=>["", "A-"], "Sam"=>["", "A-"],
# "Caleb"=>[""]}
arr1.map { |s| "#{prefixes[s].shift}#{s}" }.zip(arr2).to_h
#=> {"David"=>"1", "John"=>"2", "Alex"=>"3", "Sam"=>"4",
# "Caleb"=>"5", "A-David"=>"6", "A-John"=>"7",
# "A-Alex"=>"8", "B-John"=>"9", "A-Sam"=>"10"}
Обратите внимание, что "A-".next #=> "B-"
и "Z-".next #=> "AA-"
.
Альтернативная структура данных
Возможно, вы захотите рассмотреть другую структуру данных, которая возвращает
{"David"=>["1", "6"], "John"=>["2", "7", "9"],
"Alex" =>["3", "8"], "Sam" =>["4", "10"], "Caleb"=>["5"]}
Вы можете сделать это следующим образом.
arr1.each_with_index.
group_by(&:first).
transform_values { |v| arr2.values_at(*v.map(&:last)) }
#=> {"David"=>["1", "6"], "John"=>["2", "7", "9"],
# "Alex" =>["3", "8"], "Sam" =>["4", "10"],
# "Caleb"=>["5"]}
См. Enumerable # each_with_index , Enumerable # group_by , Hash # transform_values 1 и Array # values_at .v.map(*:last)
здесь совпадает с v.map { |arr| arr.last }
.Шаги следующие:
a = arr1.each_with_index
#=> #<Enumerator: ["David", "John", "Alex", "Sam",
# "Caleb", "David", "John", "Alex", "John", "Sam"]:
# each_with_index>
Мы можем увидеть значения, которые будут сгенерированы этим перечислителем, преобразовав его в массив.
a.to_a
#=> [["David", 0], ["John", 1], ["Alex", 2], ["Sam", 3],
# ["Caleb", 4], ["David", 5], ["John", 6], ["Alex", 7],
# ["John", 8], ["Sam", 9]]
Продолжение,
b = a.group_by(&:first)
#=> {"David"=>[["David", 0], ["David", 5]],
# "John"=> [["John", 1], ["John", 6], ["John", 8]],
# "Alex"=> [["Alex", 2], ["Alex", 7]],
# "Sam"=> [["Sam", 3], ["Sam", 9]],
# "Caleb"=>[["Caleb", 4]]}
b.transform_values { |v| arr2.values_at(*v.map(&:last)) }
#=> {"David"=>["1", "6"], "John"=>["2", "7", "9"],
# "Alex"=> ["3", "8"], "Sam"=> ["4", "10"], "Caleb"=>["5"]}
На последнем шаге первое значение хэша b
передается блоку, и этому значению присваивается переменная блока.
v = b.values.first
#=> [["David", 0], ["David", 5]]
Затем вычисления блока выполняются следующим образом.
c = v.map(&:last)
#=> [0, 5]
arr2.values_at(*c)
#=> arr2.values_at(0, 5)
#=> ["1", "6"]
Расчеты аналогичны для каждого из оставшихся значений b
, которые передаются в блок.
1.Новое в Ruby MRI v2.4.