RoR:按对象内数组长度拆分对象数组为块(单块最多12个Varieties)
优化物种批量分组方法(Ruby on Rails)
需求说明
我们有一个包含多个物种对象的数组,每个物种结构如下:
{ id: 1, name: 'Grass', varieties: [ {variety_name: 'Grass Variety'}, {variety_name: 'Grass Variety 1'}, {variety_name: 'Grass Variety 2'} ] }
需要将该数组拆分为多个批次,每个批次中所有物种的varieties总数最多为12。
原实现问题
自行实现的方法如下,但可读性与性能表现不佳:
def batch_species(species) species_batch = [] loops = 0 current_batch_value = 0 species.each do |specie| species_batch[loops] = [] if species_batch[loops].nil? next_value = current_batch_value + specie[:varieties].length if next_value >= 13 loops += 1 current_batch_value = 0 species_batch[loops] = [] end current_batch_value += 1 if specie[:varieties].empty? current_batch_value += specie[:varieties].length species_batch[loops].push(specie) end species_batch end
优化实现方案
基础版本(按实际品种数计算)
使用Ruby的each_with_object简化批次管理,逻辑更清晰:
def batch_species(species) species.each_with_object([[]]) do |specie, batches| current_batch = batches.last current_total = current_batch.sum { |s| s[:varieties].size } next_total = current_total + specie[:varieties].size if next_total > 12 batches << [specie] else current_batch << specie end end end
适配空品种场景(若业务要求空varieties按1计数)
如果业务规则要求空varieties的物种需算作1个“品种”,可调整计算逻辑:
def batch_species(species) species.each_with_object([[]]) do |specie, batches| current_batch = batches.last # 按业务规则计算单个物种的"品种权重" specie_weight = specie[:varieties].empty? ? 1 : specie[:varieties].size current_total = current_batch.sum { |s| s[:varieties].empty? ? 1 : s[:varieties].size } next_total = current_total + specie_weight if next_total > 12 batches << [specie] else current_batch << specie end end end
优化点说明
- 可读性提升:用
each_with_object初始化并维护批次数组,无需手动管理循环索引和计数变量,逻辑一目了然 - 逻辑严谨:直接通过
sum计算当前批次的品种总数,避免原方法中对空品种的冗余/错误计数(原方法中对空品种会额外+1,再+0,导致计数错误) - 性能持平:均为O(n)时间复杂度,但代码更易维护和扩展
内容的提问来源于stack exchange,提问作者rhwd
相关产品推荐
相关产品推荐

