将这个数组转换为:
a = ["item 1", "item 2", "item 3", "item 4"]
转换成哈希表:
{ "item 1" => "item 2", "item 3" => "item 4" }
即,位于偶数索引的元素是键,而奇数索引则是值。a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }
就是这样了,*
被称为splat操作符。
根据@Mike Lewis(在评论中)的建议,有一个小细节:“要非常小心。Ruby在堆栈上展开splats。如果你用大数据集来做这个,要准备爆掉你的堆栈。”
因此,在大多数一般情况下,这种方法很好,但如果您想对大量数据进行转换,请使用其他方法。例如,@Łukasz Niemier(也在评论中)提供了适用于大数据集的另一种方法:
h = Hash[a.each_slice(2).to_a]
*
被称为展开运算符。它接受一个数组,并将其转换为一个字面的项目列表。因此,*[1,2,3,4]
=> 1, 2, 3, 4
。在这个例子中,以上等同于执行Hash["item 1", "item 2", "item 3", "item 4"]
。而且,Hash
有一个[]
方法,可以接受一系列参数(使偶数索引成为键,奇数索引成为值),但是Hash []
不能接受一个数组,所以我们使用*
来展开数组。 - Ben LeeHash[a.each_slice(2).to_a]
。 - HaulethRuby 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}
只需在数组中使用Hash.[]
即可。例如:
arr = [1,2,3,4]
Hash[*arr] #=> gives {1 => 2, 3 => 4}
*arr
将 arr
转换为参数列表,因此这将使用 arr 的内容作为参数调用 Hash 的 []
方法。 - Chuck或者如果你有一个由 [key, value]
数组构成的数组,你可以这样做:
[[1, 2], [3, 4]].inject({}) do |r, s|
r.merge!({s[0] => s[1]})
end # => { 1 => 2, 3 => 4 }
Hash [*arr]
仍然更容易。 - Yossi{ [1, 2] => [3, 4] }
。由于问题的标题是“数组转哈希”,而内置的“哈希转数组”方法是:{ 1 => 2, 3 => 4}.to_a # => [[1, 2], [3, 4]]
,我认为可能有更多人试图获得内置的“哈希转数组”方法的反向操作。实际上,这就是我最终到达这里的方式。 - Erik EscobedoHash[arr]
将为您完成工作。 - Yossi#inject
方法。应该使用#merge!
和#each_with_object
。如果坚持使用#inject
,则应该使用#merge
而不是#merge!
。 - Boris Stitnicky[[1, 2], [3, 4]].to_h
。 - CTS_AE进行谷歌搜索时我找到了以下内容:
[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v }
=> {:a=>1, :b=>2}
merge
,因为它会在每个循环迭代中构建和丢弃一个新哈希,速度非常慢。如果你有一个哈希数组,请尝试使用[{a:1},{b:2}].reduce({}, :merge!)
- 它将所有内容合并到同一个(新的)哈希表中。 - user240438.reduce(&:merge!)
。 - Ben Lee[{a: 1}, {b: 2}].reduce(&:merge!)
evaluates to {:a=>1, :b=>2}
- Ben Lee[{a: 1}, {b: 2}].reduce(&:merge!)
与[{a: 1}, {b: 2}].reduce { |m, x| m.merge(x) }
相同,它们都等同于[{b: 2}].reduce({a: 1}) { |m, x| m.merge(x) }
。 - Ben Lee自从2.1
版本以来,Enumerable
中也有一个方法#to_h
,所以
包含了它。因此,我们可以这样写:Enumerator
a = ["item 1", "item 2", "item 3", "item 4"]
a.each_slice(2).to_h
# => {"item 1"=>"item 2", "item 3"=>"item 4"}
因为在不使用块的情况下,#each_slice
方法返回一个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}
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"
Hash[ ... ]
但想要像使用 to_h
那样将其用作链式方法,你可以结合Boris的建议编写以下代码:arr.each_slice( 2 ).map { |e| e }.tap { |a| break Hash[a] }
- b-studios让我们来看看:
"Original Answer"翻译成中文是"最初的回答"。
a = ["item 1", "item 2", "item 3", "item 4", "item 1", "item 5"]
item 1 => item 2
对,因为它被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"]}
一个朴素的方法是创建一个帮助变量,即具有默认值的哈希表,然后在循环中填充它:
最初的回答
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"]}
assoc
和reduce
在一行中完成上述操作,但这将变得更加难以理解和阅读。最初的回答。