将多维数组转换为哈希数组

时间:2014-09-29 21:38:17

标签: ruby

我有这些数据:

input = [ [ 'abc', '1.1' ], [ 'abc', '1.2' ], [ 'xyz', '3.14' ] ]

我想输出如下:

[ { 'abc' => [ '1.1', '1.2' ] }, { 'xyz' => '3.14' } ]

是否有可能在一个链表达式中实现这一目标?

4 个答案:

答案 0 :(得分:1)

我会这样做:

input = [['abc', '1.1'], ['abc','1.2'], ['xyz', '3.14']]

output = input.each_with_object(Hash.new{ |h, k| h[k] = [] }) { |(k, v), h| h[k] << v }
output # => {"abc"=>["1.1", "1.2"], "xyz"=>["3.14"]}

替代方案不是那么简单:

input.group_by{ |k,v| k }.map{ |k, v| [k, v.map(&:last)] }.to_h # => {"abc"=>["1.1", "1.2"], "xyz"=>["3.14"]}

您的输出结构

output: [{'abc' => ['1.1', '1.2']}, {'xyz' => '3.14'}]

使用哈希是一种非常糟糕的方式。相反,你应该有一个带有多个元素的哈希,因为你将like-key的值组合成一个键。


如果真的需要输出,就像有些人想的那样,那么只需在返回的值上添加map

input.each_with_object(Hash.new{ |h, k| h[k] = [] }) { |(k, v), h| h[k] << v }.map{ |k, v| {k => v} } 
# => [{"abc"=>["1.1", "1.2"]}, {"xyz"=>["3.14"]}]

答案 1 :(得分:0)

我能想到的最简单的方法:

input.group_by {|x| x[0]}.each_pair.map { |k, v| {k => (a=v.map(&:last)).count > 1 ? a : a[0]} }

答案 2 :(得分:0)

最简单的方法就是这样:

def convert_marray_to_hash(input)
  hash = Hash.new { |hash, key| hash[key] = [] }
  output = []

  input.each { |array| hash[array[0]] << array[1] }
  hash.keys.each { |key| output << { key => hash[key] } }      

  output
end

有很多方法可以做到这一点,但这种方式很好地呈现并且可读。

答案 3 :(得分:0)

这非常有效:

input = [ [ 'abc', '1.1' ], [ 'abc','1.2' ], [ 'xyz', '3.14' ] ]

input.each_with_object({}) do |(key, val), hsh|
  hsh[key] = val and next unless hsh.key?(key)
  hsh[key] = [ *hsh[key], val ]
end
.map {|key, val| { key => val } }
# => [ { "abc" => [ "1.1", "1.2" ] },
#      { "xyz" => "3.14" }
#    ]

如果省略最后的map,你最终会得到一个哈希,这似乎是一个更自然的结果,但这与指定的输出相匹配,至少。