Search code examples
javascriptarraysnormalize

How to normalize a list of positive numbers in JavaScript?


I have an array filled with positive int values, how could I normalize this list so the max value is always 100? Thank you in advance!


Solution

  • The idea is to first find the highest number in your array (using apply on Math.max), then find the ratio between that highest number and 100.

    After that, it's just a matter of looping through your array and dividing all your numbers by that ratio:

    var numbers = [3, 8, 45, 74, 123],
        ratio = Math.max.apply(Math, numbers) / 100,
        l = numbers.length,
        i;
    
    for (i = 0; i < l; i++) {
        numbers[i] = Math.round(numbers[i] / ratio);
    }
    

    Here's the fiddle: http://jsfiddle.net/XpRR8/


    Note: I'm using Math.round to round the numbers to the nearest integer. If you instead prefer to keep them as floats, just remove the function call:

    for ( i = 0; i < l; i++ ) {
        numbers[i] /= ratio;
    }
    

    Here's the fiddle: http://jsfiddle.net/XpRR8/1/


    If you don't have to support IE8 and below, you can use Array.prototype.map():

    var numbers = [3, 8, 45, 74, 123],
        ratio = Math.max.apply(Math, numbers) / 100;
    
    numbers = numbers.map(function (v) {
        return Math.round(v / ratio);
    });
    

    Here's the fiddle: http://jsfiddle.net/XpRR8/2/


    If you do support IE8, but are anyhow using jQuery, you can use $.map() instead:

    numbers = $.map(numbers, function (v) {
        return Math.round(v / ratio);
    });
    

    Here's the fiddle: http://jsfiddle.net/XpRR8/3/


    Update: As pointed out by @wvxvw in the comments below, if you're concerned about fringe implementations that impose an artificial limit on the amount of arguments apply will handle, then use a loop instead of Math.max.apply. Here's an example (assuming neither Array.prototype.map nor $.map are available):

    var numbers = [3, 8, 45, 74, 123],
        ratio = 0,
        i = numbers.length;
    
    while (i--) numbers[i] > ratio && (ratio = numbers[i]);
    
    ratio /= 100;
    i = numbers.length;
    
    while (i--) numbers[i] = Math.round(numbers[i] / ratio);
    

    Here's the fiddle: http://jsfiddle.net/XpRR8/4/


    If you're using ES6, this becomes laughably simple:

    var numbers = [3, 8, 45, 74, 123];
    var ratio = Math.max(...numbers) / 100;
    
    numbers = numbers.map(v => Math.round(v / ratio));