Genetic Drift Simulator - Follow Up This question is a follow-up of a previous question of mine: Genetic Drift Simulator.

Following the advice given in the last question, and some more general improvements, the code has been slimmed down a bit. The major one was implementing Underscore.js, which slimmed down a few of the loops into functions.

The config has identical properties to the last question, however, they've been renamed.


numGenerations: the number of generations to iterate over. Can be number input or infinite to go until one population remains.
population: an object containing the names of the populations and the amount of each.
drawAmount: the amount of population to be surveyed.




var GeneticDriftSimulator = function (user_config) {
    this.config = _.defaults(user_config, {
        numGenerations: '5',
        population: {
            red: 50,
            blue: 50
        },
        drawAmount: 10
    });
};

GeneticDriftSimulator.prototype.run = function () {
    var ratioPopulation = this.config.population;
    var isIndefinite = (this.config.numGenerations == 'infinite');
    for (var i = 0; isIndefinite || i &lt; this.config.numGenerations; i++) {
        if (Object.keys(ratioPopulation).length == 1) {
            console.log('Generation ' + i + ': One trait left: ' + Object.keys(ratioPopulation)[0]);
            break;
        }
        var population = [];
        for (var populationName in ratioPopulation) {
            for (var k = 0; k &lt; ratioPopulation[populationName]; k++) {
                population.push(populationName);
            }
        }
        ratioPopulation = this.ProcessGeneration(population, config.drawAmount);

        var print_result = "Generation " + i + ": ";
        Object.keys(ratioPopulation).forEach(function (key) {
            print_result += key + ':' + ratioPopulation[key] + ' '
        });
        console.log(print_result);
    }
};

GeneticDriftSimulator.prototype.ProcessGeneration = function (population, drawAmount) {
    var temp_drawn = [];
    if (config.drawAmount &gt;= population.length) {
        throw 'SimulationError: The DrawAmount is more than the Population.';
    }
    if (population.length % drawAmount != 0) {
        throw 'SimulationError: The DrawAmount cannot be evenly divided by Population';
    }

    temp_drawn = _.sample(population, drawAmount);
    var multiplier = population.length / drawAmount;
    return this.RatioCount(multiplier, temp_drawn);
};

GeneticDriftSimulator.prototype.RatioCount = function (multiplier, temp_drawn) {
    var final = {};
    _.each(temp_drawn, function (population) {
        for (var i = 0; i &lt; multiplier; i++) {
            if (!(population in final)) {
                final[population] = 0;
            }
            final[population]++;
        }
    });
    return final;
}


with usage like the following:


var config = {
    numGenerations: 'infinite',
    population: {
        cats: 3e4,
        dogs: 7e4,
    },
    drawAmount: 5e4
};
var simulation = new GeneticDriftSimulator(config);
simulation.run();
A few things to point out in retrospect:


There's inconsistent quotation marks everywhere
Lines like the following are confusing and hard to read: print_result += key + ':' + ratioPopulation[key] + ' '
These (throw) should be throw new Error as it includes a stack trace.
Don't use snake case (temp_drawn) use camel case (tempDrawn)
Be careful about using truthy value checks like (population.length % drawAmount != 0) as it can cause issues relating to booleans, for example false == 0 will return true, but false === 0 will return false. See Truthy and Falsy: When All is Not Equal in JavaScript for more information and examples.
run doesn't match the case of the other functions, it should be Run.
k &lt; ratioPopulation[populationName];: declare the length as a variable within the for loop as it gets rid of the constant length checking which can strain when you have a really large array.
You should consider using an array here instead var final = {}; as it may reduce logic on the loops.