943 votes

Trouver l'élément min/max d'un tableau en JavaScript

Comment obtenir facilement l'élément min ou max d'un tableau JavaScript ?

Exemple de pseudocode :

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100

132 votes

Note : Avec ECMAScript 6, vous pouvez utiliser la nouvelle fonction opérateur de diffusion (trois points : ... ) avec Math.max() comme ça : Math.max(...[2, 5, 16, 1]) . Voir ma réponse fait à partir de la Documentation MDN .

0 votes

Ici un point de repère pour une comparaison de vitesse des manières les plus courantes de le faire : jsben.ch/#/1QuTg

0 votes

Sans ES6 Math.max.apply(null, [2,5,16,1])

941voto

Roatin Marth Points 9532

Que diriez-vous d'augmenter l'objet Array intégré pour utiliser Math.max / Math.min à la place :

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

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

Voici un JSFiddle .

L'augmentation des modules intégrés peut provoquer des collisions avec d'autres bibliothèques (certains le voient), aussi vous serez peut-être plus à l'aise avec simplement apply 'ing Math.xxx() à votre tableau directement :

var min = Math.min.apply(null, arr),
    max = Math.max.apply(null, arr);

Alternativement, en supposant que votre navigateur supporte ECMAScript 6, vous pouvez utiliser la fonction opérateur de diffusion qui fonctionne de manière similaire à la apply méthode :

var min = Math.min( ...arr ),
    max = Math.max( ...arr );

2 votes

Cela ne devrait-il pas être "return Math.max.apply( Math, this ) ;" et non pas return Math.max.apply( null, this ) ;

4 votes

@HankH : peut-être. Math.max s'apparente à une méthode "statique", il n'y a donc pas d'utilité. this à l'intérieur de celui-ci (j'espère). Donc, en supposant que cela soit vrai, l'appeler l'exécuterait dans la portée globale (c.-à-d. window ), ce qui équivaut à passer null comme premier paramètre de apply / call .

9 votes

@HankH : passing null ou Math ou {} ou autre pour apply() ou call() n'a aucune incidence sur le résultat. Math.max ne fait pas et ne doit pas faire référence this en interne.

410voto

newspire Points 1748
var max_of_array = Math.max.apply(Math, array);

Pour une discussion complète, voir : http://aaroncrane.co.uk/2008/11/javascript_max_api/

17 votes

Quelle est la différence entre Math.max.apply(Math, array) et Math.max.apply(null, array) ? Le blog dit "...vous devez également répéter de manière redondante que max appartient à Math ...", mais il semble que je n'aie pas à le faire (en définissant le premier argument de la fonction apply comme null ).

12 votes

@ziyuang Quand tu l'appelles comme Math.max(a,b) , Math est transmis en tant que this il peut donc être judicieux de faire de même lors d'un appel avec la fonction apply . Mais Math.max n'utilise pas le this vous pouvez donc passer la valeur que vous voulez.

244voto

Linus Unnebäck Points 1855

Pour les grands tableaux (~10 éléments), Math.min et Math.max produit l'erreur suivante dans Node.js.

RangeError : La taille maximale de la pile d'appels est dépassée

Une solution plus robuste consiste à ne pas ajouter chaque élément à la pile d'appel, mais à passer un tableau :

function arrayMin(arr) {
  return arr.reduce(function (p, v) {
    return ( p < v ? p : v );
  });
}

function arrayMax(arr) {
  return arr.reduce(function (p, v) {
    return ( p > v ? p : v );
  });
}

Si vous êtes préoccupé par la vitesse, le code suivant est ~3 fois plus rapide que Math.max.apply est sur mon ordinateur. Voir http://jsperf.com/min-and-max-in-array/2 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (arr[len] < min) {
      min = arr[len];
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (arr[len] > max) {
      max = arr[len];
    }
  }
  return max;
};

Si votre tableau contient des chaînes de caractères au lieu de chiffres, vous devez également les convertir en chiffres. Le code ci-dessous le fait, mais il ralentit le code ~10 fois sur ma machine. Voir http://jsperf.com/min-and-max-in-array/3 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (Number(arr[len]) < min) {
      min = Number(arr[len]);
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (Number(arr[len]) > max) {
      max = Number(arr[len]);
    }
  }
  return max;
};

0 votes

Attribuer min et max au dernier élément et réduire les itérations de 1 ( while(--len) ) ;)

0 votes

@Venugopal alors vous avez besoin d'une vérification spéciale pour voir si le tableau est vide et retourner +/- l'infini.

3 votes

C'est étrange... Je suis allé sur le site web lié... et en testant dans Firefox 51.0.0 / Mac OS X 10.12.0, l'approche basée sur la réduction est 30% plus lente que celle basée sur la boucle ... des résultats très différents

23voto

inkedmn Points 12655

Vous le faites en étendant le type Array :

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

Stimulé par ici (par John Resig)

15voto

Ionuț G. Stan Points 62482

D'autres ont déjà donné quelques solutions dans lesquelles ils augmentent Array.prototype . Tout ce que je veux dans cette réponse est de clarifier si cela doit être Math.min.apply( Math, array ) ou Math.min.apply( null, array ) . Quel est donc le contexte à utiliser ? Math ou null ?

En passant null comme un contexte pour apply alors le contexte sera par défaut l'objet global (l'objet window dans le cas des navigateurs). Le passage de l'objet Math en tant que contexte serait la bonne solution, mais cela ne fera pas de mal de passer l'objet null soit. Voici un exemple lorsque null pourrait causer des problèmes, lors de la décoration de la Math.max fonction :

// 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);

L'opération ci-dessus entraînera une exception car this.foo sera évalué comme window.foo qui est undefined . Si nous remplaçons null avec Math les choses fonctionneront comme prévu et la chaîne de caractères "foo" sera imprimée à l'écran (j'ai testé ceci en utilisant la commande Mozilla Rhino ).

Vous pouvez supposer que personne n'a décoré Math.max donc, en passant null fonctionnera sans problème.

3 votes

C'est vrai. Cependant, pourquoi quelqu'un décorerait-il Foo.staticMethod et référence this ? Ne serait-ce pas une erreur dans la conception du décorateur ? (à moins bien sûr qu'il ne s'agisse voulant pour faire référence à la portée globale, et veulent pour rester indépendant du moteur JavaScript utilisé, par exemple Rhino).

2 votes

La spécification est explicite quant aux fonctions spécifiées qui doivent se référer à "l'outil de gestion de l'environnement". ce valeur" (en effet, cette phrase apparaît 125 fois dans la spécification). Math.max mis en œuvre conformément à la spécification, n'utilise pas this . Si quelqu'un passe outre Math.max de sorte qu'il utilise this alors ils ont fait en sorte que son comportement viole les spécifications et vous devriez leur jeter des objets pointus. Vous ne devriez pas coder autour de cette possibilité, pas plus que vous ne coderiez autour de la possibilité que quelqu'un a échangé Math.max et Math.min pour le lulz.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X