博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[转] Hash#deep_merge

Posted on 2011-03-22 09:52  |orz  阅读(301)  评论(0编辑  收藏  举报
1 # Hash#deep_merge
2 # From: http://pastie.textmate.org/pastes/30372, Elliott Hird
3 # Source: http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
4 # This file contains extensions to Ruby and other useful snippits of code.
5 # Time to extend Hash with some recursive merging magic.
6  
7
8 class Hash
9
10 # Merges self with another hash, recursively.
11 #
12 # This code was lovingly stolen from some random gem:
13 # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
14 #
15 # Thanks to whoever made it.
16
17 def deep_merge(hash)
18 target = dup
19
20 hash.keys.each do |key|
21 if hash[key].is_a? Hash and self[key].is_a? Hash
22 target[key] = target[key].deep_merge(hash[key])
23 next
24 end
25
26 target[key] = hash[key]
27 end
28
29 target
30 end
31
32
33 # From: http://www.gemtacular.com/gemdocs/cerberus-0.2.2/doc/classes/Hash.html
34 # File lib/cerberus/utils.rb, line 42
35
36 def deep_merge!(second)
37 second.each_pair do |k,v|
38 if self[k].is_a?(Hash) and second[k].is_a?(Hash)
39 self[k].deep_merge!(second[k])
40 else
41 self[k] = second[k]
42 end
43 end
44 end
45
46
47 #-----------------
48
49 # cf. http://subtech.g.hatena.ne.jp/cho45/20061122
50 def deep_merge2(other)
51 deep_proc = Proc.new { |k, s, o|
52 if s.kind_of?(Hash) && o.kind_of?(Hash)
53 next s.merge(o, &deep_proc)
54 end
55 next o
56 }
57 merge(other, &deep_proc)
58 end
59
60
61 def deep_merge3(second)
62
63 # From: http://www.ruby-forum.com/topic/142809
64 # Author: Stefan Rusterholz
65
66 merger = proc { |key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
67 self.merge(second, &merger)
68
69 end
70
71
72 def keep_merge(hash)
73 target = dup
74 hash.keys.each do |key|
75 if hash[key].is_a? Hash and self[key].is_a? Hash
76 target[key] = target[key].keep_merge(hash[key])
77 next
78 end
79 #target[key] = hash[key]
80 target.update(hash) { |key, *values| values.flatten.uniq }
81 end
82 target
83 end
84
85 end
86
87
88 h = {:a => {:b => :c}}.merge({:a => {:l => :x}})
89 p h #=> {:a=>{:l=>:x}}
90
91 h = {:a => {:b => :c}}.deep_merge({:a => {:l => :x}})
92 p h #=> {:a=>{:b=>:c, :l=>:x}}
93 puts
94
95
96 h1 = {:a => {:b => :c}}
97 h2 = {:a => {:l => :x}}
98
99 h = h1.deep_merge(h2)
100 p h1, h2, h
101 puts
102
103 h = h1.deep_merge2(h2)
104 p h1, h2, h
105 puts
106
107 h = h1.deep_merge!(h2)
108 p h1, h2, h
109
110
111 h1 = {:a => {:b => :c}}
112 h2 = {:a => {:l => :x}}
113
114 p h1.deep_merge3(h2)
115 p h1, h2
116
117
118 first = {
119 :data=>{
120 :name=>{
121 :first=>'Sam',
122 :middle=>'I',
123 :last=>'am'
124 }
125 }
126 }
127
128 second={
129 :data=>{
130 :name=>{
131 :middle=>'you',
132 :last=>'are'
133 }
134 }
135 }
136
137
138 p first.deep_merge3(second)
139 #=> {:data=>{:name=>{:middle=>"you", :first=>"Sam", :last=>"are"}}}
140
141 p first.keep_merge(second)
142 #=> {:data=>{:name=>{:first=>"Sam", :middle=>["I", "you"], :last=>["am", "are"]}}}