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.