top | item 2377022

Fast JavaScript Max/Min

62 points| DanielRibeiro | 15 years ago |ejohn.org | reply

17 comments

order
[+] nkassis|15 years ago|reply
I used his technique for a while but then I had to find the max and min of an array of 1 million values which is more than the maximum number of arguments to a function in most javascript implementation so I rewrote it a such:

Array.prototype.min = function() {

  var increment = 50000;

  if(this.length > increment){

    var reduced_array = [];

    for(var i=0;i<this.length;i+=increment) {

      reduced_array.push(Math.min.apply(Math, 
this.slice(i,i+increment-1))); }

  }else {

    return Math.min.apply(Math, this);


  }

  return reduced_array.min();

}; Array.prototype.max = function(array) {

  var increment = 50000;

  if(this.length > increment){

    var reduced_array = [];

    for(var i=0;i<this.length;i+=increment) {

      reduced_array.push(Math.max.apply(Math, this.slice(i,i+increment-1)));

    }

  }else {

    return Math.max.apply(Math, this);
  }
I'm sure someone can suggest a better way.
[+] qixxiq|15 years ago|reply
They way you've done it seems fine, although if you're trying to find minimums of such large arrays in javascript I'd assume you're doing something wrong.

Javascript really isn't a great choice of language for big processing tasks; stuff like that should be moved away where possible (granted it isn't always an option).

[+] utkarshkukreti|15 years ago|reply
It might be faster to write the code, but it's definitely not the fastest way to find the minimum/maximum value. Some simple test cases I wrote show a simple for loop iterator over an array to be 2x faster than Math.min.apply in Firefox 4, and 3x faster in Chrome 10.

http://jsperf.com/fastest-array-min-max

[+] dspillett|15 years ago|reply
If you take out the (currently unused: it is updated but never referred to afterwards) the first-index-of-the-smallest-value-was-found-at variable the difference in FF is even larger.

These are the results on FF 3.6.16 on my desktop:

    ~33.5 ops/sec (million test, using Array.min.apply)
    ~57.0 o/s     (with index var)
    ~86.5 o/s     (without index var)
I'm a little surprised it makes that much difference (I assumed the two set operations, one of which I removed, would be less significant than that in the execution timings compared to the array object lookup in the comparison, given JS arrays aren't actually arrays strictly speaking). The difference may be less significant (zero, in fact) with a JS engine that does dead-code analysis that successfully works out that min_i is set in the loop but otherwise never used.
[+] jacobolus|15 years ago|reply
Underscore.js is pretty good about delegating to built-in functions when available in its little utility functions. http://documentcloud.github.com/underscore/docs/underscore.h...
[+] jashkenas|15 years ago|reply
The real reason why Underscore doesn't use "Math.max.apply" and "Math.min.apply", is that they only work on small arrays of numbers. After you get beyond 40-50,000-ish (last time I checked), some browsers will throw an exception because you can't pass that many arguments to a function.

I remember running into this in real-world code, trying to calculate the brightest pixel in a <canvas> imageData array.

[+] tzury|15 years ago|reply
They surely missed this one though.

as Underscore.js do this:

     _.max = function(obj, iterator, context) {
        if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
        var result = {computed : -Infinity};
        each(obj, function(value, index, list) {
          var computed = iterator ? iterator.call(context, value, index, list) : value;
          computed >= result.computed && (result = {value : value, computed : computed});
        });
        return result.value;
     };


     _.min = function(obj, iterator, context) {
        if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
        var result = {computed : Infinity};
        each(obj, function(value, index, list) {
          var computed = iterator ? iterator.call(context, value, index, list) : value;
          computed < result.computed && (result = {value : value, computed : computed});
        });
        return result.value;
     };

While John do that:

    Array.max = function( array ){
      return Math.max.apply( Math, array );
    };
    Array.min = function( array ){
      return Math.min.apply( Math, array );
    };
[+] clvv|15 years ago|reply
> Posted: January 13th, 2007

That's four years ago.

[+] gobongo|15 years ago|reply
> 4 points by clvv 2 hours ago | link | parent | flag

That's 2 hours ago.

[+] stevoski|15 years ago|reply
In the post, he asks this question: "What's the fastest way to find the largest, or smallest, number in an array?"

I guess he means fastest code to write, not the fastest code to run. If you have, say, a million numbers, I'd try doing this using concurrency. If there are two CPUs (or cores), find the maximum in the bottom half of the array and the maximum in the top half in parallel. Then return the maximum of the two maximums.

I don't know much JavaScript - does it have built-in support for concurrency?