You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

更优雅地访问/修改结构固定的嵌套JSONB单位数据的方法

优化Ruby中JSONB单位数据的嵌套循环访问

问题背景

我的模型中存在一个固定包含ground和naval键的JSONB结构,用于存储单位数据,示例如下:

{
  "ground" => {
    "infantry" => 1, "artillery" => 1
  }, 
  "naval" => {
    "battleships" => 1, "carriers" => 1
  }
}

由于诸多方法都需要访问底层单位数据,导致出现大量类似以下的双重嵌套循环代码:

new_units.each do |battle_type, _value|
  new_units[battle_type].each do |type, quantity|
    damaged_unit_quantity += HEALING_TICK_RATE * healing_ticks
    new_units[battle_type][type] = quantity.floor + [damaged_unit_quantity, 1].min
  end
end

其中HEALING_TICK_RATE、healing_ticks和damaged_unit_quantity均为浮点数。需要更具可读性的方式,避免重复使用双重嵌套循环来访问/修改ground和naval下的单位。


解决方案

1. 提取通用迭代方法

将遍历所有单位的逻辑封装成单独方法,后续操作单位时只需关注业务逻辑,无需重复编写嵌套循环:

def each_unit(units)
  units.each_value do |category_units|
    category_units.each do |type, quantity|
      yield(type, quantity, category_units)
    end
  end
end

# 使用示例
each_unit(new_units) do |type, quantity, category|
  damaged_unit_quantity += HEALING_TICK_RATE * healing_ticks
  category[type] = quantity.floor + [damaged_unit_quantity, 1].min
end

2. 扁平化单位结构

通过flat_map将嵌套结构转为一维数组,简化批量操作逻辑:

# 扁平化所有单位为 [单位类型, 数量, 所属类别] 的数组
all_units = new_units.flat_map do |category, units|
  units.map { |type, qty| [type, qty, category] }
end

# 对扁平化后的数组执行操作
all_units.each do |type, quantity, category|
  damaged_unit_quantity += HEALING_TICK_RATE * healing_ticks
  new_units[category][type] = quantity.floor + [damaged_unit_quantity, 1].min
end

3. 封装为面向对象的单位集合类

将JSONB数据封装成专用类,把所有单位操作逻辑内聚,彻底摆脱嵌套循环:

class UnitCollection
  HEALING_TICK_RATE = 0.1 # 可根据实际需求调整

  def initialize(data)
    @data = data
  end

  def heal!(healing_ticks)
    damaged_unit_quantity = 0.0
    each_unit do |type, quantity|
      damaged_unit_quantity += HEALING_TICK_RATE * healing_ticks
      # 定位并修改对应单位数量
      category = type.split('_')[0] # 假设单位类型与类别匹配,如 infantry 属于 ground
      @data[category][type] = quantity.floor + [damaged_unit_quantity, 1].min
    end
    @data
  end

  private

  def each_unit(&block)
    @data.each_value do |category|
      category.each(&block)
    end
  end

  # 可扩展其他方法,如消耗单位、统计总数量等
end

# 使用示例
unit_collection = UnitCollection.new(new_units)
updated_units = unit_collection.heal!(healing_ticks)

4. 用transform_values!简化嵌套修改

利用Ruby哈希的transform_values!方法直接修改层级值,代码更简洁:

healing_amount = HEALING_TICK_RATE * healing_ticks
damaged_unit_quantity = 0.0

new_units.transform_values! do |category_units|
  category_units.transform_values! do |quantity|
    damaged_unit_quantity += healing_amount
    quantity.floor + [damaged_unit_quantity, 1].min
  end
end

内容的提问来源于stack exchange,提问作者xxcellerator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 08:52:42