Ruby
1obj1 = { a: 3, b: { c: 1, d: [ 6, 3 ], e: 2 } }
2obj2 = { a: 1, b: { c: 2, d: [ 2, 0, 4 ], f: 1 } }
3obj3 = { b: { d: [ 1 ] } }
4
5def merge(*object)
6 {}.merge(*object) do |k, v1, v2|
7 if Array===v1 and Array===v2
8 if v1.size < v2.size
9 v1 << [nil] * (v2.size-v1.size)
10 end
11 v1.zip(v2).flatten.compact
12 elsif Hash===v1 and Hash===v2
13 merge(v1,v2)
14 else
15 v2
16 end
17 end
18end
19
20p merge(obj1, obj2, obj3)
21#=> {:a=>1, :b=>{:c=>2, :d=>[6, 1, 2, 3, 0, 4], :e=>2, :f=>1}}
で良いかと思ったのですが、結果が、
plain
1{:a=>1, :b=>{:c=>2, :d=>[6, 1, 2, 3, 0, 4], :e=>2, :f=>1}}
になります。
:d=>[6, 2, 1, 3, 0, 4]
にするためには、Arrayのマージをハッシュのマージが全部終わってから行う必要があるので、かなり面倒ですが、興味がわいたのでやってみました。
Ruby
1obj1 = { a: 3, b: { c: 1, d: [ 6, 3 ], e: 2 } }
2obj2 = { a: 1, b: { c: 2, d: [ 2, 0, 4 ], f: 1 } }
3obj3 = { b: { d: [ 1 ] } }
4
5class Foo
6 def initialize(x)
7 @x = [x]
8 end
9 def add(x)
10 @x << x
11 self
12 end
13 def merge
14 l = @x.map(&:size).max
15 ([nil]*l).zip(*@x).flatten.compact
16 end
17end
18
19def merge_sub(*object)
20 {}.merge(*object) do |k, v1, v2|
21 if Array===v1 and Array===v2
22 Foo.new(v1).add(v2)
23 elsif Foo===v1 and Array===v2
24 v1.add(v2)
25 elsif Hash===v1 and Hash===v2
26 merge_sub(v1,v2)
27 else
28 v2
29 end
30 end
31end
32
33def transform_sub(hash)
34 hash.transform_values do |v|
35 case v
36 when Foo
37 v.merge
38 when Hash
39 transform_sub(v)
40 else
41 v
42 end
43 end
44end
45
46def merge(*object)
47 transform_sub(merge_sub(*object))
48end
49
50p merge(obj1, obj2, obj3)
51#=> {:a=>1, :b=>{:c=>2, :d=>[6, 2, 1, 3, 0, 4], :e=>2, :f=>1}}