ruby 将 2 元素数组的数组转换为哈希,其中重复的键附加附加值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9270972/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 04:45:52  来源:igfitidea点击:

Convert array of 2-element arrays into a hash, where duplicate keys append additional values

rubyarrayshash

提问by smallsense

For example

例如

Given an array:

给定一个数组:

array = [[:a,:b],[:a,:c],[:c,:b]]

Return the following hash:

返回以下哈希:

hash = { :a => [:b,:c] , :c => [:b] }

hash = Hash[array]overwrites previous associations, producing:

hash = Hash[array]覆盖以前的关联,产生:

hash = { :a => :c , :c => :b }

回答by Phrogz

Using functional baby steps:

使用功能性婴儿步骤:

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]}

Using imperative style programming:

使用命令式编程:

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]}

As an imperative one-liner:

作为必要的单行:

irb:13.0> h = Hash.new{ |h,k| h[k]=[] }.tap{ |h| array.each{ |k,v| h[k] << v } }
#=> {:a=>[:b, :c], :c=>[:b]}

Or using everyone's favorite inject:

或者使用大家最喜欢的inject

irb:14.0> array.inject(Hash.new{ |h,k| h[k]=[] }){ |h,(k,v)| h[k] << v; h }
#=> {:a=>[:b, :c], :c=>[:b]}

If you really want to have single values not collided as an array, you can either un-array them as a post-processing step, or use a different hash accumulation strategy that only creates an array upon collision. Alternatively, wrap your head around this:

如果您真的希望单个值不会作为数组发生冲突,您可以将它们取消排列作为后处理步骤,或者使用不同的散列累积策略,仅在冲突时创建数组。或者,将您的头围绕在此:

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}

回答by Abdo

EDIT:In Ruby 2.1+, you can use Array#to_h

编辑:在 Ruby 2.1+ 中,您可以使用Array#to_h

pry(main)> [[:a,:b],[:a,:c],[:c,:b]].to_h
=> {:a=>:c, :c=>:b}

END EDIT

结束编辑

The public [] method on the Hash class accepts a key-value pair array and returns a hash with the first element of the array as key and the second as value.

Hash 类上的 public [] 方法接受一个键值对数组,并返回一个哈希,其中数组的第一个元素作为键,第二个元素作为值。

The last value in the key-value pair will be the actual value when there are key duplicates.

键值对中的最后一个值将是键重复时的实际值。

Hash[[[:a,:b],[:a,:c],[:c,:b]]]
    => {:a=>:c, :c=>:b}

This syntax is valid in 1.9.3+ ; I'm not sure about earlier Ruby versions (it's not valid in 1.8.7)

此语法在 1.9.3+ 中有效;我不确定早期的 Ruby 版本(它在 1.8.7 中无效)

ref: http://www.ruby-doc.org/core-2.1.0/Hash.html#method-c-5B-5D

参考:http: //www.ruby-doc.org/core-2.1.0/Hash.html#method-c-5B-5D

Another interesting way of doing it would be using the inject method: (obviously the method above is more succinct and recommended for this specific problem)

另一个有趣的方法是使用注入方法:(显然上面的方法更简洁,推荐用于这个特定问题)

[ [:a, :b], [:a, :c], [:c, :b] ].inject({}) { |memo, obj| 
   memo[obj.first] = obj.last
   memo 
}

=> {:a=>:c, :c=>:b}

inject iterates over the enumerable, your array in this case, starting with the injected parameter, in this case the empty hash {}.

inject 迭代可枚举,在这种情况下是您的数组,从注入的参数开始,在这种情况下是空哈希 {}。

For each object in the enumerable, the block is called with the variables memo and obj:

对于可枚举中的每个对象,使用变量 memo 和 obj 调用块:

  • obj is the current object in the array

  • memo is the value that has been returned by your block's last iteration (for the first iteration, it's what you inject)

  • obj 是数组中的当前对象

  • memo 是块的最后一次迭代返回的值(对于第一次迭代,它是您注入的)

回答by Ian

This can be done fairly succinctly using each_with_object.

这可以使用each_with_object.

array.each_with_object({}) { |(k, v), h| h[k] = (h[k] || []) + [v] }

Demonstrating in irb:

展示在irb

irb(main):002:0> array = [[:a,:b],[:a,:c],[:c,:b]]
=> [[:a, :b], [:a, :c], [:c, :b]]
irb(main):003:0> array.each_with_object({}) { |(k, v), h| h[k] = (h[k] || []) + [v] }
=> {:a=>[:b, :c], :c=>[:b]}