ruby 如何在Ruby中合并多个哈希?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19548496/
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
How to merge multiple hashes in Ruby?
提问by B Seven
h = { a: 1 }
h2 = { b: 2 }
h3 = { c: 3 }
Hash#merge works for 2 hashes: h.merge(h2)
Hash#merge 适用于 2 个哈希: h.merge(h2)
How to merge 3 hashes?
如何合并3个哈希?
h.merge(h2).merge(h3)works but is there a better way?
h.merge(h2).merge(h3)有效,但有更好的方法吗?
回答by hirolau
You could do it like this:
你可以这样做:
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}
Edit: This is probably the correct way to do it if you have many hashes:
编辑:如果你有很多散列,这可能是正确的方法:
a.inject{|tot, new| tot.merge(new)}
# or just
a.inject(&:merge)
回答by Oleg Afanasyev
Since Ruby 2.0on that can be accomplished more graciously:
由于Ruby 2.0可以更优雅地完成:
h.merge **h1, **h2
And in case of overlapping keys - the latter ones, of course, take precedence:
在重叠键的情况下 - 当然,后者优先:
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}
回答by jayqui
You can just do
你可以做
[*h,*h2,*h3].to_h
# => {:a=>1, :b=>2, :c=>3}
This works whether or not the keys are Symbols.
无论键是否为Symbols,这都有效。
回答by SRack
Ruby 2.6 allows mergeto take multiple arguments:
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}
This works with Hash.merge!and Hash.updatetoo. Docs for this here.
这也适用于Hash.merge!和Hash.update。此处的文档。
Also takes empty hashes and keys as symbols orstrings.
还将空散列和键作为符号或字符串。
Much simpler :)
简单得多:)
回答by Matt
Answer using reduce(same as inject)
使用reduce(与 相同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"}
Explanation
解释
For those beginning with Ruby or functional programming, I hope this brief explanation might help understand what's happening here.
对于那些开始使用 Ruby 或函数式编程的人,我希望这个简短的解释可以帮助理解这里发生的事情。
The reducemethod when called on an Array object (hash_arr) will iterate through each element of the array with the returned value of the block being stored in an accumulator (acc). Effectively, the hparameter of my block will take on the value of each hash in the array, and the accparameter will take on the value that is returned by the block through each iteration.
reduce在 Array 对象 ( hash_arr)上调用该方法时,将迭代数组的每个元素,并将块的返回值存储在累加器 ( acc) 中。实际上,h我的块的acc参数将采用数组中每个散列的值,并且参数将采用块通过每次迭代返回的值。
We use (acc || {})to handle the initial condition where accis nil. Note that the mergemethod gives priority to keys/values in the original hash. This is why the value of "bar2b"doesn't appear in my final hash.
我们(acc || {})用来处理初始条件,其中acc为 nil。请注意,该merge方法优先考虑原始散列中的键/值。这就是为什么 的值"bar2b"没有出现在我的最终哈希中的原因。
Hope that helps!
希望有帮助!
回答by David
class Hash
def multi_merge(*args)
args.unshift(self)
args.inject { |accum, ele| accum.merge(ele) }
end
end
That should do it. You could easily monkeypatch that into Hash as I have shown.
那应该这样做。正如我所展示的那样,您可以轻松地将其猴子补丁到 Hash 中。
回答by Tim Lowrimore
To build upon @Oleg Afanasyev's answer, you can also do this neat trick:
要以@Oleg Afanasyev 的回答为基础,您还可以使用这个巧妙的技巧:
h = { a: 1 }
h2 = { b: 2 }
h3 = { c: 3 }
z = { **h, **h2, **h3 } # => {:a=>1, :b=>2, :c=>3}
Cheers!
干杯!
回答by AGS
newHash = [h, h2, h3].each_with_object({}) { |oh, nh| nh.merge!(oh)}
# => {:a=>1, :b=>2, :c=>3}
回答by animatedgif
Here are the 2 monkeypatched ::Hash instance methods we use in our app. Backed by Minitest specs. They use merge!instead of mergeinternally, for performance reasons.
这是我们在应用程序中使用的 2 个monkeypatched ::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
Tests:
测试:
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
回答by Boris Stitnicky
Just for fun, you can do it also this way:
只是为了好玩,你也可以这样做:
a = { a: 1 }, { b: 2 }, { c: 3 }
{}.tap { |h| a.each &h.method( :update ) }
#=> {:a=>1, :b=>2, :c=>3}

