Optimization suggestions for Javascript

Given this code:

    var minX = minY = maxX = maxY = 0;

    for(var i=0; i<objArray.length; i++){
        if(objArray[i].x < minX){
            minX = objArray[i].x;
        }else if(objArray [i].x > maxX){
            maxX = objArray[i].x;
        }
        if(objArray[i].y < minY){
            minY = objArray[i].y;
        }else if(objArray [i].y > maxY){
            maxY = objArray[i].y;
        }
    }

      

It works, but I don't think it's very nifty. This is simple logic, but it uses 10 lines of code. Can you improve?

+2


source to share


3 answers


You can use Math.min and Math.max :

var minX = minY = Number.POSITIVE_INFINITY,
    maxX = maxY = Number.NEGATIVE_INFINITY;

for(var i=0; i<objArray.length; i++){
  minX = Math.min(objArray[i].x, minX);
  minY = Math.min(objArray[i].y, minY);
  maxX = Math.max(objArray[i].x, maxX);
  maxY = Math.max(objArray[i].y, maxY);
}

      

To optimize the loop speed, you can store the length so that it can be calculated only once:

for(var i=0, len = objArray.length; i<len; i++){
  //...
}

      

For more information on loop optimization see the article .

Another approach, just for "functional fun" as I wouldn't recommend it for performance, would be to strip the x and y values ​​down to two arrays using Array.map , and then call the min and max functions using apply :

var allX = objArray.map(function (o) { return o.x; });
var allY = objArray.map(function (o) { return o.y; });

minX = Math.min.apply(Math, allX);
minY = Math.min.apply(Math, allY);
maxX = Math.max.apply(Math, allX);
maxY = Math.max.apply(Math, allY);

      



How it works?

The apply function is used to call another function with a given context and arguments presented as an array. The min and max functions can take an arbitrary number of input arguments: Math.max (val1, val2, ..., valN)

So if we call:

Math.min.apply(Math, [1,2,3,4]);

      

The apply function will do:

Math.min(1,2,3,4);

      

Note that the first parameter, context, is not important to these functions, as they are static, they will work regardless of what is passed as context.

+10


source


it uses up to 10 lines of code.

LoC is not an optimization measure.

I have tested the above algorithms in Firefox 3.5. (See below for a test case.)

Your original code (methodA) was almost twice as fast as the CMS (methodB)! Using Math.min makes its version more readable, and in most cases this is important. But it introduces more search queries and features and slows them down.

"The functional fun version (methodC) was actually significantly faster than any version! This came as a surprise to me as this version has to create two temporary arrays, but it seems like using the apply () app for all comparisons in one go will compensate This is, however, in Firefox where there is a built-in implementation of Array.map (). Browsers like IE that do not have this feature require hacking the JavaScript version in the Array prototype, which made method C slow like methodB was for me.



The alternative functional version of Steveth was, as expected, very slow; all these temporary objects charge a fee.

In the end, the fastest I could handle was taking the original method A and setting it up to remove access to the .length loop and micro-optimizing access to multiple properties. Surprisingly, this (methodE) went crazy.

However, these are usually very browser specific. I've only tested one browser; you can get different results on others. Usually micro-optimizations don't pay off and you're better off going with the most readable option.

<script type="text/javascript">
    var objArray= [];
    for (var i= 0; i<1000000; i++) {
        objArray.push({'x': Math.floor(Math.random()*100000), 'y': Math.floor(Math.random()*100000)});
    }

    function methodA() {
        var t= new Date();
        var minX = minY = maxX = maxY = 0;
        for(var i=0; i<objArray.length; i++){
                if(objArray[i].x < minX){
                        minX = objArray[i].x;
                }else if(objArray [i].x > maxX){
                        maxX = objArray[i].x;
                }
                if(objArray[i].y < minY){
                        minY = objArray[i].y;
                }else if(objArray [i].y > maxY){
                        maxY = objArray[i].y;
                }
        }
        alert(new Date()-t);
    }
    function methodB() {
        var t= new Date();
        var minX = minY = Number.POSITIVE_INFINITY,
            maxX = maxY = Number.NEGATIVE_INFINITY;
        for(var i=0; i<objArray.length; i++){
          minX = Math.min(objArray[i].x, minX);
          minY = Math.min(objArray[i].y, minY);
          maxX = Math.max(objArray[i].x, maxX);
          maxY = Math.max(objArray[i].y, maxY);
        }
        alert(new Date()-t);
    }
    function methodC() {
        var t= new Date();
        var allX = objArray.map(function (o) { return o.x; });
        var allY = objArray.map(function (o) { return o.y; });

        minX = Math.min.apply(Math, allX);
        minY = Math.min.apply(Math, allY);
        maxX = Math.max.apply(Math, allX);
        maxY = Math.max.apply(Math, allY);
        alert(new Date()-t);
    }
    function methodD() {
        var t= new Date();
        var minX = objArray.reduce( function(a,b) { return {x : Math.min(a.x,b.x)};}).x;
        var minY = objArray.reduce( function(a,b) { return {y : Math.min(a.y,b.y)};}).y;
        var maxX = objArray.reduce( function(a,b) { return {x : Math.max(a.x,b.x)};}).x;
        var maxY = objArray.reduce( function(a,b) { return {y : Math.max(a.y,b.y)};}).y;
        alert(new Date()-t);
    }
    function methodE() {
        var t= new Date();
        var minX = minY = maxX = maxY = 0;
        var o, v;
        for (var i=objArray.length; i-->0;) {
            o= objArray[i];
            v= o.x;
            if (v<minX) minX= v;
            if (v>maxX) maxX= v;
            v= o.y;
            if (v<minY) minY= v;
            if (v>maxY) maxY= v;
        }
        alert(new Date()-t);
    }
</script>
<button onclick="methodA()">A</button>
<button onclick="methodB()">B</button>
<button onclick="methodC()">C</button>
<button onclick="methodD()">D</button>
<button onclick="methodE()">E</button>

      

+5


source


All answers so far seem to be using uninitialized variables (minX, etc.) in the comparison. Here's a functional, elegant solution:

var minX = anarray.reduce( function(a,b) { return {x : Math.min(a.x,b.x)};}).x;
var minY = anarray.reduce( function(a,b) { return {y : Math.min(a.y,b.y)};}).y;
var maxX = anarray.reduce( function(a,b) { return {x : Math.max(a.x,b.x)};}).x;
var maxY = anarray.reduce( function(a,b) { return {y : Math.max(a.y,b.y)};}).y;

      

Take a look here for an explanation of the shortening feature and how to enable it in browsers that don't support it.

+1


source







All Articles