在ruby中合并n维哈希和求和值

kyvafyod  于 2023-05-17  发布在  Ruby
关注(0)|答案(3)|浏览(224)

我正在尝试在ruby中实现一个逻辑来合并n维哈希。如果它们有相同的密钥,我会寻找它们的值的和
我有一个方法,它在每次迭代时返回一个像这样的哈希:
迭代1 { a: { count: 1, b: { count: 2 } } }
迭代2 { a: { count: 3, b: { count: 5, c: { count: 7 } } } }
迭代3 { a: { count: 3, b: { count: 2 } } }
当我合并每次迭代时,结果是{:a=>{:count=>3, :b=>{:count=>2}}}
实际上我需要count值的总和:
{ a: { count: 7, b: { count: 9, c: { count: 7 } } } }
我试过merge与块,但它不适合我。
你知道吗?

xjreopfe

xjreopfe1#

我有一个方法,它在每次迭代时返回一个像这样的哈希:[...]
让我们使用这个来进行演示:

def my_hashes
  return enum_for(__method__) unless block_given?

  yield({ a: { count: 1, b: { count: 2 } } })
  yield({ a: { count: 3, b: { count: 5, c: { count: 7 } } } })
  yield({ a: { count: 3, b: { count: 2 } } })
end

我正在尝试在ruby中实现一个逻辑来合并n维哈希。
Rails已经提供了deep_merge!来实现:

result = {}

my_hashes.each do |h|
  result.deep_merge!(h)
end

result
#=> {:a=>{:count=>3, :b=>{:count=>2, :c=>{:count=>7}}}}

如果它们有相同的密钥,我会寻找它们的值的和
默认情况下,它将 * 覆盖 * 现有值。要将每个新值与现有值相加,可以向deep_merge!传递一个块:(就像你可以使用Ruby的内置merge!一样)

result = {}

my_hashes.each do |h|
  result.deep_merge!(h) { |_, a, b| a + b }
end

result
#=> {:a=>{:count=>7, :b=>{:count=>9, :c=>{:count=>7}}}}
baubqpgj

baubqpgj2#

输入

hashes = [
  { a: { count: 1, b: { count: 2 } } },
  { a: { count: 3, b: { count: 5, c: { count: 7 } } } },
  { a: { count: 3, b: { count: 2 } } }
]

编码

def merge_hashes(hashes)
  hashes.reduce do |acc, h|
    acc.merge(h) do |key, acc_val, h_val|
      if acc_val.is_a?(Hash) && h_val.is_a?(Hash)
        merge_hashes([acc_val, h_val])
      else
        acc_val + h_val
      end
    end
  end
end

result = merge_hashes(hashes)
p result

输出

{:a=>{:count=>7, :b=>{:count=>9, :c=>{:count=>7}}}}
6qftjkof

6qftjkof3#

@Stefan是完全正确的,既然你有Rails,你应该使用他们的答案。
如果你需要一个只使用Ruby的解决方案,我做了这个。可以优化。

class Hash
  def depth
    arr = values
    d = 0
    loop do
      arr = arr.flatten.select { |e| e.is_a? Hash }
      break d if arr.empty?
      d += 1
      arr = arr.map(&:values)
    end
  end

  def deep_merge_and_count!(hsh)
    keys.each do |key|
      self[key][:count] += hsh[key][:count] if key?(key) && hsh.key?(key)

      value = self[key].except(:count)
      value.deep_merge_and_count!(hsh[key]) if value.is_a?(Hash)
    end
  end
end

hsh_one =   {a: {count: 1, b: {count: 2}}}
hsh_two =   {a: {count: 3, b: {count: 5, c: {count: 7}}}}
hsh_three = {a: {count: 3, b: {count: 2}}}
goal =      {a: {count: 7, b: {count: 9, c: {count: 7}}}}

# act upon the deepest hash, which is placed last in the array
ary_of_hshs = [hsh_one, hsh_two, hsh_three].sort_by(&:depth)
deepest_hsh = ary_of_hshs.last.dup

ary_of_hshs[0..-2].each { |hsh| deepest_hsh.deep_merge_and_count!(hsh) }

deepest_hsh == goal
# => true

相关问题