首先考虑B的每个元素都在A中的情况,如问题示例:
A = [1,2,3,4,5,6,7,8,9,10]
B = [3,6,1,5,1,2,1,6]
可以编写以下代码,只需要一次通过A(构造g1)和一次通过B。
g = A.each_with_object({}) { |n,h| h[n] = 1 }
#=> {1=>1, 2=>1, 3=>1, 4=>1, 5=>1, 6=>1, 7=>1, 8=>1, 9=>1, 10=>1}
B.each_with_object(g) { |n,h| h[n] += 1 }.flat_map { |k,v| [k]*(v-1) }
#=> [1, 1, 1, 2, 3, 5, 6, 6]
如果不能保证B 的所有元素都在A 中,并且任何没有的元素都放在排序数组的末尾,可以稍微改变g 的计算。
g = (A + (B-A)).each_with_object({}) { |n,h| h[n] = 1 }
这需要再通过 A 和 B。
假设,例如,
A = [2,3,4,6,7,8,9]
和B 不变。那么,
g = (A + (B-A)).each_with_object({}) { |n,h| h[n] = 1 }
#=> {2=>1, 3=>1, 4=>1, 6=>1, 7=>1, 8=>1, 9=>1, 1=>1, 5=>1}
B.each_with_object(g) { |n,h| h[n] += 1 }.flat_map { |k,v| [k]*(v-1) }
#=> [2, 3, 6, 6, 1, 1, 1, 5]
此解决方案展示了在 Ruby v1.9 中对哈希属性进行的有争议更改的价值:此后哈希将保证保持键插入顺序。
1 我希望可以写g = A.product([1]).to_h,但文档Array#to_h 不保证返回的哈希中的键与A 中的键具有相同的顺序。