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
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
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 );
Cela ne devrait-il pas être "return Math.max.apply( Math, this ) ;" et non pas return Math.max.apply( null, this ) ;
@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
.
@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.
var max_of_array = Math.max.apply(Math, array);
Pour une discussion complète, voir : http://aaroncrane.co.uk/2008/11/javascript_max_api/
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
).
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;
};
@Venugopal alors vous avez besoin d'une vérification spéciale pour voir si le tableau est vide et retourner +/- l'infini.
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
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.
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).
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 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.
132 votes
Note : Avec ECMAScript 6, vous pouvez utiliser la nouvelle fonction opérateur de diffusion (trois points :
...
) avecMath.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])
0 votes
Dans ES6, obtenir le maximum et le minimum peut être fait avec un seul
reduce
appelez .