更优雅地访问/修改结构固定的嵌套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
相关产品推荐
相关产品推荐

