views:

1026

answers:

8

How can I easily obtain the min and max values from a JavaScript Array?

Example code:

var arr = new Array();
arr[0] = 100;
arr[1] = 0;
arr[2] = 50;

// something like (but it doesn't have to be)
arr.min(); // return 0
arr.max(); // return 100
A: 

This may suit your purposes.

Array.prototype.min = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.min);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}

Array.prototype.max = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.max);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}
ChaosPandion
you should initialize your v with 'this[0]' in case no numbers are smaller than 0
Jason w
Thanks, nice catch.
ChaosPandion
Is `comparer` supposed to be called in some specific scope? Because as is it references `this[index]` which is `undefined` everytime.
Roatin Marth
Fixed, I always forget about function level scoping.
ChaosPandion
Oh now, now @Ionut G. Stan will critique you for the same "wrong context" argument as he did me, since your default comparer (`Math.xxx`) will be running in the global scope...
Roatin Marth
That may be true, but the new function signature requires no scope as it takes the 2 objects that needs to be compared.
ChaosPandion
A: 

You can use Array.sort but you'll have to write a simple number sorting function since the default is alphabetic.

Look at example 2 here.

Then you can grab arr[0] and arr[arr.length-1] to get min and max.

Pablo
The question is about min/max, not sorting.
Ates Goral
@Ates Goral - certainly, but surely you can understand that a sorted list allows O(1) access to the min and max values, yes?
Peter Bailey
Performance wise the sort would have a lot more swapping going on. That has to come in to consideration.
ChaosPandion
I agree that sorting is a simple approach that works; however, the performance concerns that @ChaosPandion pointed out are real.
Justin Johnson
+12  A: 

How about augmenting the built-in Array object to use Math.max/Math.min instead:

Array.prototype.max = function() {
  return Math.max.apply(null, this)
}

Array.prototype.min = function() {
  return Math.min.apply(null, this)
}

Augmenting the built-ins can cause collisions with other libraries (some see), so you may be more comfortable with just apply'ing Math.xxx() to your array directly:

var min = Math.min.apply(null, arr),
    max = Math.max.apply(null, arr);
Roatin Marth
Shouldn't that be "return Math.max.apply( Math, this );" and not return Math.max.apply( null, this );
HankH
@HankH: maybe. `Math.max` is akin to a "static" method, so there is no useful `this` instance inside of it (I hope). So assuming that is true, calling it would run it in the global scope (i.e. `window`), which is equivalent to passing `null` as the first paramter to `apply`/`call`.
Roatin Marth
+1 Very complete answer. Awesome.
Ates Goral
What about non-numbers?
ChaosPandion
What about "Array.prototype.max = function(){ return Math.max.apply({},this)}"
HankH
@HankH: passing `null` or `Math` or `{}` or whatever to `apply()` or `call()` has no bearing on the outcome. `Math.max` does not nor should not reference `this` internally.
Roatin Marth
The OP doesn't seem to have a requirement on being able to handle non-numbers.
Ates Goral
@ChaosPandion: you are absolutely right. This does not work on any other type.
Roatin Marth
+1 OP implies numeric types.
Jamie
As a C# programmer I require strongly typed questions.
ChaosPandion
+1 This is a fine example of how to use this language.
Justin Johnson
A: 

Is this homework? You need to add a prototype to the array class which defines a function for min and max and then write some code that traverses the array storing the greatest or least value it's found.

For fun, I'm going to do half of this for you with jQuery:

x=Array();
jQuery.extend(x,{
  min:function(){
    var n=Number.MAX_VALUE;
    for(i=0;i<this.length;i++){
      if(this[i]<n){
        n=this[i];
    }}
    return n;},
    max:function(){var n=Number.MIN_VALUE;for(i=0;i<this.length;i++){if(this[i]>n){n=this[i];}}return n;}
});
dlamblin
I am not downing your answer, but I must ask why you have all the code scrunched together?
ChaosPandion
Before I posted it it was a one-liner.
dlamblin
A: 

Iterate through, keeping track as you go.

var min = null;
var max = null;
for (var i = 0, len = arr.length; i < len; ++i)
{
    var elem = arr[i];
    if (min === null || min > elem) min = elem;
    if (max === null || max < elem) max = elem;
}
alert( "min = " + min + ", max = " + max );

This will leave min/max null if there are no elements in the array. Will set min and max in one pass if the array has any elements.

tvanfosson
A: 

ChaosPandion's solution works if you're using protoype. If not, consider this:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};

Array.min = function( array ){
    return Math.min.apply( Math, array );
};

The above will return NaN if an array value is not an integer so you should build some functionality to avoid that. Otherwise this will work.

jeerose
jeerose, why do you have (Math, this) as agruments when Roatin Marth only has (null, this)?
HankH
@HankH: see my response to your comment in a comment to my own answer.
Roatin Marth
I don't understand what you mean by "ChaosPandion's solution works if you're using protoype". How is your solution different, except you're using the `Math` object as the context?
Ionuț G. Stan
Please explain how mine only works if you use prototype.
ChaosPandion
Sorry, I meant if you extend the prototype yours will work. Apologies.
jeerose
So which is better, jeerose or ChaosPandion's?
HankH
what about "Array.prototype.max = function(){ return Math.max.apply({},this)}"
HankH
This looks oddly familiar to what @inkedmn posted, down to the syntax spacing and bracketing. Only his has a link to his reference (also oddly familiar). Hmmmm ;)
Roatin Marth
Okay right you are Roatin; I should have referenced it. My mistake for sure.
jeerose
+4  A: 

You do it by extending the Array type:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};
Array.min = function( array ){
    return Math.min.apply( Math, array );
};

Boosted from here (by John Resig)

inkedmn
+2  A: 

Others have already given some solutions in which they augment Array.prototype. All I want in this answer is to clarify whether it should be Math.min.apply( Math, array ) or Math.min.apply( null, array ). So what context should be used, Math or null?

When passing null as a context to apply, then the context will default to the global object (the window object in the case of browsers). Passing the Math object as the context would be the correct solution, but it won't hurt passing null either. Here's an example when null might cause trouble, when decorating the Math.max function:

// decorate Math.max
(function (oldMax) {
    Math.max = function () {
        this.foo(); // call Math.foo, or at least that's what we want

        return oldMax.apply(this, arguments);
    };
})(Math.max);

Math.foo = function () {
    print("foo");
};

Array.prototype.max = function() {
  return Math.max.apply(null, this); // <-- passing null as the context
};

var max = [1, 2, 3].max();

print(max);

The above will throw an exception because this.foo will be evaluated as window.foo, which is undefined. If we replace null with Math, things will work as expected and the string "foo" will be printed to the screen (I tested this using Mozilla Rhino).

You can pretty much assume that nobody has decorated Math.max so, passing null will work without problems.

Ionuț G. Stan
Point taken. However why would someone decorate `Foo.staticMethod` and reference `this`? Would that not be a mistake in the design of the decorator? (unless of course they were *wanting* to reference the global scope, and *want* to remain independent of the JavaScript engine being used, eg Rhino).
Roatin Marth