Home > Software design >  RoR: Separate array of objects into chunks using length of array value inside each object
RoR: Separate array of objects into chunks using length of array value inside each object

Time:10-01

I have the current array of objects containing many species inside. Species are the following:

{
id: 1,
name: 'Grass',
varieties: [
 {variety_name: 'Grass Variety'},
 {variety_name: 'Grass Variety 1'},
 {variety_name: 'Grass Variety 2'}
]
}

For each of the chunks I should have a maximum of 12 Varieties, adding up from the species.

for that, I came up with a solution of my own:

  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

I would like to know if there's any method that I can use to make this same work. Because as you can see this is not very readable, nor the most performatic.

CodePudding user response:

As so often happens, the developer chooses array column types rather than making a separate table. It almost never is a good idea. In my opinion the architecture should be:

class Specie < ApplicationRecord
  has_many :varieties
end

class Variety < ApplicationRecord
  belongs_to :specie, counter_cache: true
end

Then you can take advantage of ActiveRecord's association_count feature. In this case the Specie class has a column called varieties_count. Then a running total of the number of varieties is maintained, even as they are added or removed from the Specie instance.

This makes the collection of batches with the sum of varieties_count values <= 12 much easier.

Next you can load all the species at once (if the number is not too great! Otherwise load in batches) and take from the list until you just exceed the 12 threshold. It's still a bit time consuming, but doesn't require a db fetch for each Specie.

  • Related