Например
Учитывая массив:
array = [[:a,:b],[:a,:c],[:c,:b]]
Возвращает следующий хеш:
hash = { :a => [:b,:c] , :c => [:b] }
hash = Hash[array]
перезаписывает предыдущие ассоциации, производя:
hash = { :a => :c , :c => :b }
Учитывая массив:
array = [[:a,:b],[:a,:c],[:c,:b]]
Возвращает следующий хеш:
hash = { :a => [:b,:c] , :c => [:b] }
hash = Hash[array]
перезаписывает предыдущие ассоциации, производя:
hash = { :a => :c , :c => :b }
Использование функциональных шагов ребенка:
irb:01.0> array = [[:a,:b],[:a,:c],[:c,:b]]
#=> [[:a, :b], [:a, :c], [:c, :b]]
irb:02.0> array.group_by(&:first)
#=> {:a=>[[:a, :b], [:a, :c]], :c=>[[:c, :b]]}
irb:03.0> array.group_by(&:first).map{ |k,a| [k,a.map(&:last)] }
#=> [[:a, [:b, :c]], [:c, [:b]]]
irb:04.0> Hash[ array.group_by(&:first).map{ |k,a| [k,a.map(&:last)] } ]
#=> {:a=>[:b, :c], :c=>[:b]}
Использование программирования поэтапного стиля:
irb:10.0> h = Hash.new{ |h,k| h[k]=[] }
#=> {}
irb:11.0> array.each{ |k,v| h[k] << v }
#=> [[:a, :b], [:a, :c], [:c, :b]]
irb:12.0> h
#=> {:a=>[:b, :c], :c=>[:b]}
В качестве императивного однострочного интерфейса:
irb:13.0> h = Hash.new{ |h,k| h[k]=[] }.tap{ |h| array.each{ |k,v| h[k] << v } }
#=> {:a=>[:b, :c], :c=>[:b]}
Или используя всех любимых inject
:
irb:14.0> array.inject(Hash.new{ |h,k| h[k]=[] }){ |h,(k,v)| h[k] << v; h }
#=> {:a=>[:b, :c], :c=>[:b]}
Если вы действительно хотите, чтобы одиночные значения не сталкивались в качестве массива, вы можете либо разбить их как шаг последующей обработки, либо использовать другую стратегию накопления хэшей, которая создает массив при столкновении. В качестве альтернативы оберните вокруг себя:
irb:17.0> hashes = array.map{ |pair| Hash[*pair] } # merge many mini hashes
#=> [{:a=>:b}, {:a=>:c}, {:c=>:b}]
irb:18.0> hashes.inject{ |h1,h2| h1.merge(h2){ |*a| a[1,2] } }
#=> {:a=>[:b, :c], :c=>:b}
EDIT: В Ruby 2.1+ вы можете использовать Array # to_h
pry(main)> [[:a,:b],[:a,:c],[:c,:b]].to_h
=> {:a=>:c, :c=>:b}
END EDIT
Открытый [] метод в классе Hash принимает массив пар ключ-значение и возвращает хеш с первым элементом массива как ключ, а второй как значение.
Последнее значение в паре ключ-значение будет фактическим значением при наличии дубликатов ключей.
Hash[[[:a,:b],[:a,:c],[:c,:b]]]
=> {:a=>:c, :c=>:b}
Этот синтаксис действителен в 1.9.3+; Я не уверен в более ранних версиях Ruby (он недействителен в 1.8.7)
ref: http://www.ruby-doc.org/core-2.1.0/Hash.html#method-c-5B-5D
Еще один интересный способ сделать это - использовать метод инъекции: (очевидно, вышеописанный метод более краток и рекомендуется для этой конкретной проблемы)
[ [:a, :b], [:a, :c], [:c, :b] ].inject({}) { |memo, obj|
memo[obj.first] = obj.last
memo
}
=> {:a=>:c, :c=>:b}
вводит итерации по перечислимому, ваш массив в этом случае, начиная с введенного параметра, в этом случае пустой хэш {}.
Для каждого объекта в перечислимом блоке вызывается переменная memo и obj:
obj - текущий объект в массиве
memo - это значение, которое было возвращено последней итерацией вашего блока (для первой итерации, это то, что вы вводите)