Как преобразовать в Ruby список пар ключ-значение в хэш, чтобы значения с повторяющимися ключами сохранялись в массиве?

Учитывая пары ключ-значение списка, в виде массива массивов - например. [ ["key1","value1"], ["key2","value2"], ["key1", "value3"] ], как самым элегантным образом преобразовать их в хэш, в котором хранятся все значения?

Для приведенного выше примера я хотел бы получить { "key1" => [ "value1", "value3" ], "key2" => [ "value2" ] }.


person Guss    schedule 24.07.2015    source источник
comment
Этот вопрос уже был stackoverflow.com/questions/9270972/   -  person Ruslan Kornienko    schedule 24.07.2015
comment
Я не нашел его, когда искал, и этот вопрос не совсем то, что мне нужно, хотя в утвержденном ответе есть то, что мне нужно, и если бы я видел его раньше, я бы не задал вопрос :-)   -  person Guss    schedule 24.07.2015


Ответы (4)


Другой способ — использовать форму Hash#update (также известный как merge!), который использует блок для определения значений ключей, находящихся в обоих объединяемых хэшах.

arr = [ ["key1","value1"], ["key2","value2"], ["key1", "value3"] ]

arr.each_with_object({}) { |(k,v),h| h.update(k=>[v]) { |_,o,n| o+n } }
  #=> {"key1"=>["value1", "value3"], "key2"=>["value2"]}
person Cary Swoveland    schedule 26.07.2015
comment
Или, используя более знакомую мне семантику: arr.inject({}) { |h,(k,v)| h.merge!(k=>[v]) { |k,o,n| o+n } }. Хотя ответ @sawa был первым, мне это решение нравится больше, так как в нем меньше движущихся частей и его легче читать. - person Guss; 26.07.2015

Мое лучшее решение на данный момент таково:

kvlist.inject(Hash.new([])) do |memo,a| 
  memo[a[0]] = (memo[a[0]] << a[1])
  memo
end

Что я считаю не очень хорошо.

person Guss    schedule 24.07.2015
comment
Использовать блокировку. Сейчас этот хэш возвращает один и тот же массив для несуществующих ключей. См. ответ @test. - person D-side; 24.07.2015
comment
Итак, что-то вроде kvlist.inject(Hash.new {|h,k| h[k] = [] }) { |h,a| h[a0] << a[1]; h; } ? - person Guss; 24.07.2015

person    schedule
comment
Извините, что не принял ваш ответ - он был хорошим, соответствовал параметрам и был раньше, но я думаю, что ответ @Cary - лучшее решение. - person Guss; 26.07.2015

person    schedule
comment
Это действительно улучшение, хотя массив генерируется другим процессом, и я как бы надеялся сохранить эту маленькую функциональность, то есть kvlist -> dictionary -> operate on dictionary. - person Guss; 24.07.2015
comment
@Гасс, я тебя не понял - person Vrushali Pawar; 24.07.2015
comment
Что-то вроде @sawa, которое делает это в одной строке, а результат можно использовать, добавляя другое выражение. - person Guss; 24.07.2015