h = { a: 1 }
h2 = { b: 2 }
h3 = { c: 3 }
Hash#merge适用于2个哈希表:h.merge(h2)
如何合并3个哈希表?
h.merge(h2).merge(h3)
可以实现,但是否有更好的方法?
你可以像这样做:
h, h2, h3 = { a: 1 }, { b: 2 }, { c: 3 }
a = [h, h2, h3]
p Hash[*a.map(&:to_a).flatten] #= > {:a=>1, :b=>2, :c=>3}
编辑:如果你有很多哈希值,这可能是正确的做法:
a.inject{|tot, new| tot.merge(new)}
# or just
a.inject(&:merge)
array.reduce(&:merge)
将会得到与inject
相同的结果(inject
只是reduce
的别名)。 - ocodoHash[]
会接受一系列的参数并将它们配对构建成哈希表。因此,如果你通过a.map(&:to_a).flatten
从哈希表中生成一个有序数组,并使用展开运算符将它们作为参数传递,那么它将很好地工作。然而,Hash[]
也接受一个由k-v对表示的2元数组的数组,我会将其写成Hash[*a.flat_map(&:to_a)]
。 - Brennan从Ruby 2.0开始,这可以更加优雅地完成:
h.merge **h1, **h2
在出现重叠键的情况下,后面的键会优先生效:
h = {}
h1 = { a: 1, b: 2 }
h2 = { a: 0, c: 3 }
h.merge **h1, **h2
# => {:a=>0, :b=>2, :c=>3}
h.merge **h2, **h1
# => {:a=>1, :c=>3, :b=>2}
**
是什么意思? - Arnold Roah1
和h2
是{}
,它会引发错误。h.merge(**{},**{})
- tiagomenegaz你只需要做
[*h,*h2,*h3].to_h
# => {:a=>1, :b=>2, :c=>3}
无论键是不是 Symbol
,这都可以运行。
Ruby 2.6 允许 merge
接受多个参数:
h = { a: 1 }
h2 = { b: 2 }
h3 = { c: 3 }
h4 = { 'c' => 4 }
h5 = {}
h.merge(h2, h3, h4, h5) # => {:a=>1, :b=>2, :c=>3, "c"=>4}
这也适用于Hash.merge!
和Hash.update
。有关此内容的文档在此处。
还可以接受空哈希和键作为符号或者字符串。
简单得多 :)
ArgumentError: wrong number of arguments (given 2, expected 1)
错误。 - Rajan Verma - Aarvyreduce
(与inject
相同)来回答hash_arr = [{foo: "bar"}, {foo2: "bar2"}, {foo2: "bar2b", foo3: "bar3"}]
hash_arr.reduce { |acc, h| (acc || {}).merge h }
# => {:foo2=>"bar2", :foo3=>"bar3", :foo=>"bar"}
对于那些刚开始接触Ruby或函数式编程的人,我希望这个简短的解释可以帮助理解这里正在发生什么。
当在一个数组对象(hash_arr
)上调用reduce
方法时,它将迭代数组中的每个元素,并将块返回的值存储在累加器(acc
)中。实际上,我的块的h
参数将采用数组中每个哈希表的值,而acc
参数将采用通过每次迭代返回的值。
我们使用(acc || {})
来处理acc
为空的初始条件。请注意,merge
方法优先考虑原始哈希表中的键/值。这就是为什么"bar2b"
的值没有出现在我的最终哈希表中的原因。
希望这可以帮到你!
reduce
和 inject
中,累加器(或备忘录)作为初始参数传递给块,而不是最后一个参数,这与此建议不同(不像 each_with_object
)。 - engineersmnkyh = { a: 1 }
h2 = { b: 2 }
h3 = { c: 3 }
z = { **h, **h2, **h3 } # => {:a=>1, :b=>2, :c=>3}
干杯!
class Hash
def multi_merge(*args)
args.unshift(self)
args.inject { |accum, ele| accum.merge(ele) }
end
end
newHash = [h, h2, h3].each_with_object({}) { |oh, nh| nh.merge!(oh)}
# => {:a=>1, :b=>2, :c=>3}
#merge!
而不是#merge
。在这种情况下,#merge
别名#update
速度显著更快。 - Boris Stitnicky这是我们应用程序中使用的两个猴子补丁的::Hash实例方法。支持Minitest规范。出于性能原因,它们在内部使用merge!
而不是merge
。
class ::Hash
# Merges multiple Hashes together. Similar to JS Object.assign.
# Returns merged hash without modifying the receiver.
#
# @param *other_hashes [Hash]
#
# @return [Hash]
def merge_multiple(*other_hashes)
other_hashes.each_with_object(self.dup) do |other_hash, new_hash|
new_hash.merge!(other_hash)
end
end
# Merges multiple Hashes together. Similar to JS Object.assign.
# Modifies the receiving hash.
# Returns self.
#
# @param *other_hashes [Hash]
#
# @return [Hash]
def merge_multiple!(*other_hashes)
other_hashes.each(&method(:merge!))
self
end
end
测试:
describe "#merge_multiple and #merge_multiple!" do
let(:hash1) {{
:a => "a",
:b => "b"
}}
let(:hash2) {{
:b => "y",
:c => "c"
}}
let(:hash3) {{
:d => "d"
}}
let(:merged) {{
:a => "a",
:b => "y",
:c => "c",
:d => "d"
}}
describe "#merge_multiple" do
subject { hash1.merge_multiple(hash2, hash3) }
it "should merge three hashes properly" do
assert_equal(merged, subject)
end
it "shouldn't modify the receiver" do
refute_changes(->{ hash1 }) do
subject
end
end
end
describe "#merge_multiple!" do
subject { hash1.merge_multiple!(hash2, hash3) }
it "should merge three hashes properly" do
assert_equal(merged, subject)
end
it "shouldn't modify the receiver" do
assert_changes(->{ hash1 }, :to => merged) do
subject
end
end
end
end
只是为了好玩,你也可以这样做:
a = { a: 1 }, { b: 2 }, { c: 3 }
{}.tap { |h| a.each &h.method( :update ) }
#=> {:a=>1, :b=>2, :c=>3}
merge
函数可以接收多个哈希作为参数。更多信息请参见这里。 - SRack