数组到哈希Ruby

转换这个数组:

a = ["item 1", "item 2", "item 3", "item 4"]

...到哈希值:

{ "item 1" => "item 2", "item 3" => "item 4" }

即,甚至索引上的元素是,而奇怪的索引上的元素是

216264 次浏览
a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }

就是这样。*被称为长条木板操作符。

@Mike Lewis(在评论中)提醒一句:“要非常小心。Ruby在堆栈上扩展splat。如果你用一个大型数据集来做这件事,预计会让你的堆栈崩溃。”

因此,对于大多数一般的用例,这种方法是很好的,但如果您想对大量数据进行转换,请使用不同的方法。例如,@Łukasz Niemier(也在评论中)为大型数据集提供了这种方法:

h = Hash[a.each_slice(2).to_a]

只要对数组中的值使用Hash.[]即可。例如:

arr = [1,2,3,4]
Hash[*arr] #=> gives {1 => 2, 3 => 4}

或者如果你有一个[key, value]数组,你可以这样做:

[[1, 2], [3, 4]].inject({}) do |r, s|
r.merge!({s[0] => s[1]})
end # => { 1 => 2, 3 => 4 }
a = ["item 1", "item 2", "item 3", "item 4"]
Hash[ a.each_slice( 2 ).map { |e| e } ]

或者,如果你讨厌Hash[ ... ]:

a.each_slice( 2 ).each_with_object Hash.new do |(k, v), h| h[k] = v end

或者,如果你是坏函数式编程的懒粉丝:

h = a.lazy.each_slice( 2 ).tap { |a|
break Hash.new { |h, k| h[k] = a.find { |e, _| e == k }[1] }
}
#=> {}
h["item 1"] #=> "item 2"
h["item 3"] #=> "item 4"

Ruby 2.1.0在Array上引入了to_h方法,如果你的原始数组由键值对数组组成,它就可以完成你所需要的:http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-to_h

[[:foo, :bar], [1, 2]].to_h
# => {:foo => :bar, 1 => 2}

Enumerator包括Enumerable。从2.1开始,Enumerable也有一个方法#to_h。这就是为什么,我们可以写:-

a = ["item 1", "item 2", "item 3", "item 4"]
a.each_slice(2).to_h
# => {"item 1"=>"item 2", "item 3"=>"item 4"}

因为没有block的#each_slice会给我们Enumerator,并且根据上面的解释,我们可以在Enumerator对象上调用#to_h方法。

你可以这样尝试,对于单个数组

irb(main):019:0> a = ["item 1", "item 2", "item 3", "item 4"]
=> ["item 1", "item 2", "item 3", "item 4"]
irb(main):020:0> Hash[*a]
=> {"item 1"=>"item 2", "item 3"=>"item 4"}

对于数组的数组

irb(main):022:0> a = [[1, 2], [3, 4]]
=> [[1, 2], [3, 4]]
irb(main):023:0> Hash[*a.flatten]
=> {1=>2, 3=>4}

这就是我在谷歌上搜索这个的时候想要的:

< p > <代码> [{:1},{b: 2}] .reduce ({}) {| h、v | h.merge v} =比;{: a =祝辞;1:b =祝辞2} < /代码> < / p >

所有答案都假设起始数组是唯一的。OP没有指定如何处理具有重复条目的数组,这会导致重复的键。

让我们来看看:

a = ["item 1", "item 2", "item 3", "item 4", "item 1", "item 5"]

你将失去item 1 => item 2对,因为它被覆盖了bij item 1 => item 5:

Hash[*a]
=> {"item 1"=>"item 5", "item 3"=>"item 4"}

所有的方法,包括reduce(&:merge!)都会导致相同的删除。

不过,这可能正是你所期望的。但在其他情况下,你可能想要得到一个Array作为值的结果:

{"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}

naïve的方法是创建一个辅助变量,一个有默认值的散列,然后在循环中填充:

result = Hash.new {|hash, k| hash[k] = [] } # Hash.new with block defines unique defaults.
a.each_slice(2) {|k,v| result[k] << v }
a
=> {"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}

也许可以在一行中使用assocreduce来完成上述操作,但这将变得更加难以推理和阅读。