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

779

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

Exemple de pseudo-code:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100
HankH
la source
93
Note: Avec ECMAScript 6 , vous pouvez utiliser le nouvel opérateur de diffusion (trois points: ...) avec Math.max()comme ceci: Math.max(...[2, 5, 16, 1]). Voir ma réponse faite à partir de la documentation MDN .
totymedli
1
Envisagez de marquer une réponse comme acceptée.
Alex
ici une référence pour une comparaison de vitesse des façons les plus courantes de le faire: jsben.ch/#/1QuTg
EscapeNetscape
es6 est fondamentalement superbe! :)
datdinhquoc
Sans ES6 Math.max.apply(null, [2,5,16,1])
Tomer

Réponses:

828

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

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

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

Voici un JSFiddle .

Augmenter les Encastrements peut provoquer des collisions avec d' autres bibliothèques (certains voient), donc vous pouvez être plus à l' aise avec juste 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 prend en charge ECMAScript 6, vous pouvez utiliser l' opérateur d'étalement qui fonctionne de manière similaire à la applyméthode:

var min = Math.min( ...arr ),
    max = Math.max( ...arr );
Roatin Marth
la source
8
@HankH: passer nullou Mathou {}ou quoi que ce soit à apply()ou call()n'a aucune incidence sur le résultat. Math.maxne fait ni ne doit faire référence en thisinterne.
Roatin Marth
31
En tant que programmeur C #, j'ai besoin de questions fortement typées.
ChaosPandion
7
Je partage juste une erreur jQuery que je faisais avec le code ci-dessus, ce qui m'a mis beaucoup de temps à déboguer. Un tableau jquery fonctionne bien sur tout sauf l'iPad. J'ai dû convertir le tableau en un véritable tableau natif pour qu'il fonctionne. Affecté uniquement le périphérique unique pour une raison quelconqueMath.max.apply(null, $.makeArray(array));
Forrest
11
J'ai rétrogradé, car l'approche proposée consomme de la mémoire O (n) dans le cadre de la pile et, par conséquent, se bloque sur les grands tableaux. Dans mon cas, environ 130000 numéros étaient suffisants pour planter nodejs.
Alexey Timanovsky
14
N'augmentez pas les prototypes intégrés comme celui-ci. Il ne s'agit pas seulement de conflits avec d'autres bibliothèques; il s'agit également de la possibilité que le navigateur lui-même fournisse une méthode .maxou .minà l'avenir. Scénario parfaitement réaliste: vous utilisez cette réponse. En 2016, spécification ES7 ou ES8 Array.maxet Array.min. Contrairement à cette version, ils fonctionnent sur des chaînes. Votre futur collègue essaie d'obtenir la dernière chaîne alphabétique dans un tableau avec la .max()méthode native désormais bien documentée , mais l'obtient mystérieusement NaN. Quelques heures plus tard, elle trouve ce code, exécute un git blameet maudit votre nom.
Mark Amery
362
var max_of_array = Math.max.apply(Math, array);

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

flot de nouvelles
la source
13
Quelle est la difference entre Math.max.apply(Math, array)et Math.max.apply(null, array)? Le blog dit "... vous devez également redire redondamment qui maxappartient à Math...", mais il semble que je ne doive pas le faire (en définissant le premier argument de applyas null).
ziyuang
9
@ziyuang Lorsque vous l'appelez comme Math.max(a,b), Mathest passé en tant que thisvaleur, il peut donc être judicieux de faire de même lors de l'appel avec apply. Mais Math.maxn'utilise pas la thisvaleur, vous pouvez donc transmettre la valeur que vous souhaitez.
Oriol
199

Pour les grands tableaux (~ 10⁷ éléments), Math.minet les Math.maxdeux produisent l'erreur suivante dans Node.js.

RangeError: dépassement de la taille maximale de la pile d'appels

Une solution plus robuste consiste à ne pas ajouter tous les éléments à la pile d'appels, mais à passer à la place 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 environ 3 fois plus rapide que Math.max.applysur 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 vos tableaux contiennent des chaînes au lieu de nombres, vous devez également les contraindre en nombres. Le code ci-dessous fait cela, 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;
};
Linus Unnebäck
la source
affecter minet maxau dernier élément et réduire les itérations de 1 ( while(--len));)
Venugopal
@Venugopal alors vous avez besoin d'une vérification spéciale pour voir si le tableau est vide et retourner +/- Infinity
Linus Unnebäck
2
É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 sur la boucle ... des résultats très différents
Pierpaolo Cira
2
very different results vous l'avez fait 5 ans plus tard)
Алексей Лещук
1
En 2019, la reducesolution est la plus lente. Même si vous travaillez avec un tableau contenant des millions d'éléments, il est préférable d'utiliser la norme for loop . Voir ma réponse pour en savoir plus.
totymedli
152

Utilisation de l'opérateur d'étalement (ES6)

Math.max(...array);  // the same with "min" => Math.min(...array);

Abdennour TOUMI
la source
8
Cette solution a déjà été fournie par plusieurs autres réponses.
totymedli
15
Math.max (... []) = -Infinity. hahaha 😂😂😂
David Portabella
@DavidPortabella ne sais pas pourquoi c'est drôle. Voilà comment cela fonctionne selon les spécifications :If no arguments are given, the result is -∞.
Patrick Roberts
3
oui, je voulais dire que la spécification javascript est horrible. Il semble évident que le min sans nombre ne peut pas être calculé. Dans d'autres langages de programmation plus sérieux, comme Scala, demander le min d'un tableau vide lève une exception.
David Portabella
3
Scala s'adresse aux personnes qui ont besoin d'une machine pour leur dire qu'elles l'ont mal fait
thedanotto
107

tl; dr

// For regular arrays:
var max = Math.max(...arrayOfNumbers);

// For arrays with tens of thousands of items:
let max = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
  if (testArray[i] > max) {
    max = testArray[i];
  }
}

Solution MDN

La documentation officielle de MDN surMath.max() couvre déjà ce problème:

La fonction suivante utilise Function.prototype.apply () pour rechercher l'élément maximal dans un tableau numérique. getMaxOfArray([1, 2, 3])est équivalent à Math.max(1, 2, 3), mais vous pouvez l'utiliser getMaxOfArray()sur des tableaux construits par programmation de n'importe quelle taille.

function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}

Ou avec le nouvel opérateur d'étalement , obtenir le maximum d'un tableau devient beaucoup plus facile.

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

Taille maximale d'un tableau

Selon MDN, les applysolutions et spread avaient une limitation de 65536 qui provenait de la limite du nombre maximum d'arguments:

Mais attention: en utilisant Appliquer de cette façon, vous courez le risque de dépasser la limite de longueur d'argument du moteur JavaScript. Les conséquences de l'application d'une fonction avec trop d'arguments (pensez à plus de dizaines de milliers d'arguments) varient selon les moteurs ( JavaScriptCore a une limite d'arguments codée en dur de 65536 ), car la limite (en fait même la nature de toute pile trop grande) comportement) n'est pas spécifié. Certains moteurs lèveront une exception. Plus pernicieusement, d'autres limiteront arbitrairement le nombre d'arguments réellement passés à la fonction appliquée. Pour illustrer ce dernier cas: si un tel moteur avait une limite de quatre arguments (les limites réelles sont bien sûr significativement plus élevées), ce serait comme si les arguments 5, 6, 2, 3 avaient été passés pour s'appliquer dans les exemples ci-dessus, plutôt que le tableau complet.

Ils fournissent même une solution hybride qui n'a pas vraiment de bonnes performances par rapport à d'autres solutions. Voir test de performance ci-dessous pour en savoir plus.

En 2019, la limite réelle est la taille maximale de la pile d'appels . Pour les navigateurs de bureau modernes basés sur Chromium, cela signifie que lorsqu'il s'agit de trouver min / max avec applyou étalé, la taille maximale des tableaux uniquement numériques est d'environ 120000 . Au-dessus de cela, il y aura un débordement de pile et l'erreur suivante sera levée:

RangeError: dépassement de la taille maximale de la pile d'appels

Avec le script ci-dessous (basé sur cet article de blog ), en détectant cette erreur, vous pouvez calculer la limite de votre environnement spécifique.

Attention! L'exécution de ce script prend du temps et selon les performances de votre système, il peut ralentir ou planter votre navigateur / système!

let testArray = Array.from({length: 10000}, () => Math.floor(Math.random() * 2000000));
for (i = 10000; i < 1000000; ++i) {
  testArray.push(Math.floor(Math.random() * 2000000));
  try {
    Math.max.apply(null, testArray);
  } catch (e) {
    console.log(i);
    break;
  }
}

Performances sur de grandes baies

Sur la base du test dans le commentaire d' EscapeNetscape , j'ai créé des repères qui testent 5 méthodes différentes sur un tableau de nombres aléatoires uniquement avec 100 000 éléments .

En 2019, les résultats montrent que la boucle standard (dont BTW n'a pas la limitation de taille) est la plus rapide partout. applyet la propagation suit de près, puis beaucoup plus tard la solution hybride de MDN, puis reducela plus lente.

Presque tous les tests ont donné les mêmes résultats, sauf un où la propagation s'est avérée être la plus lente.

Si vous augmentez votre tableau pour avoir 1 million d'articles, les choses commencent à se casser et vous vous retrouvez avec la boucle standard comme solution rapide et reduceplus lente.

Référence JSPerf

jsperf.com résultats de référence pour différentes solutions pour trouver l'élément min / max d'un tableau

Référence JSBen

Résultats de référence jsben.com pour différentes solutions pour trouver l'élément min / max d'un tableau

Référence JSBench.me

Résultats de référence jsbench.me pour différentes solutions pour trouver l'élément min / max d'un tableau

Code source de référence

totymedli
la source
Si vous utilisez le dactylographe, l'opérateur d'étalement comme indiqué est compilé pour Math.max.apply(Math, arr)une compatibilité «max».
Simon_Weaver
1
Aussi de MDN: "les deux se propagent (...)et applyéchouent ou renvoient le mauvais résultat si le tableau contient trop d'éléments [...] La solution de réduction n'a pas ce problème" En testant Chrome, FF, Edge et IE11, il semble que ce soit le cas ok pour un tableau de jusqu'à 100k valeurs. (Testé sur Win10 et les derniers navigateurs: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam
C'est une méthode très lente, que se passe-t-il si le tableau contient des milliers d'éléments?
Slava Fomin II
@SlavaFominII J'ai étendu la réponse pour qu'elle couvre les tableaux avec des milliers d'éléments.
totymedli
68

Si vous êtes paranoïaque comme moi à propos de l'utilisation Math.max.apply(ce qui pourrait provoquer des erreurs lors de la fourniture de grands tableaux selon MDN ), essayez ceci:

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.max(a, b);
  });
}

function arrayMin(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  });
}

Ou, dans ES6:

function arrayMax(array) {
  return array.reduce((a, b) => Math.max(a, b));
}

function arrayMin(array) {
  return array.reduce((a, b) => Math.min(a, b));
}

Les fonctions anonymes sont malheureusement nécessaires (au lieu d'utiliser Math.max.bind(Math)parce reduceque ne passe pas seulement aet bà sa fonction, mais aussi iet une référence au tableau lui-même, nous devons donc nous assurer que nous n'essayons pas de les appeler maxégalement.

Daniel Buckmaster
la source
Votre exemple ES6, y a-t-il une raison de ne pas simplement revenir Math.max(...array)?
Wojciech Bednarski
@WojciechBednarski cette page semble suggérer que l'utilisation de l'opérateur d'étalement équivaut à passer un tableau à apply, et a donc les mêmes inconvénients (limite d'argument maximale).
Daniel Buckmaster
Merci pour cela. Vous pouvez juste corriger le support manquant après la réduction:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky
1
@DanielDietrich Je suppose que faire l'équivalent, appeler Math.min()sans valeur, renvoie Infinity, donc ces fonctions pourraient utiliser reduce(..., Infinity)pour correspondre à ce comportement. Je préfère cependant qu'il lance une exception (comme il le fait actuellement), car prendre le minimum d'un tableau vide semble être une erreur.
Daniel Buckmaster
1
jusqu'ici réduire est le plus lent.
Алексей Лещук
40

.apply est souvent utilisé lorsque l'intention est d'invoquer une fonction variadique avec une liste de valeurs d'argument, par exemple

La Math.max([value1[,value2, ...]])fonction renvoie le plus grand de zéro ou plusieurs nombres.

Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20

La Math.max()méthode ne vous permet pas de passer dans un tableau. Si vous avez une liste de valeurs dont vous avez besoin pour obtenir la plus grande, vous appelez normalement cette fonction en utilisant Function.prototype.apply () , par exemple

Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20

Cependant, à partir de l' ECMAScript 6, vous pouvez utiliser l' opérateur d'étalement :

L'opérateur spread permet à une expression d'être développée aux endroits où plusieurs arguments (pour les appels de fonction) ou plusieurs éléments (pour les littéraux de tableau) sont attendus.

En utilisant l'opérateur d'étalement, les éléments ci-dessus peuvent être réécrits comme tels:

Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20

Lors de l'appel d'une fonction à l'aide de l'opérateur variadic, vous pouvez même ajouter des valeurs supplémentaires, par exemple

Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50

Prime:

Opérateur de propagation vous permet d'utiliser le tableau syntaxe littérale pour créer de nouveaux tableaux dans des situations où ES5 vous auriez besoin de revenir à un code impératif, en utilisant une combinaison de push, spliceetc.

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']
Gajus
la source
1
Votre dernier exemple dans le bonus serait écrit à l'aide concatde la plupart des programmeurs car il vous permet de conserver un style de ligne unique.
Cody Allan Taylor
31

Deux façons sont plus courtes et faciles:

let arr = [2, 6, 1, 0]

Voie 1 :

let max = Math.max.apply(null, arr)

Voie 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});
Hafizur Rahman
la source
Attention si le tableau est vide - vous obtiendrez une infinité négative qui peut ne pas être ce que vous voulez. Si vous préférez obtenir, 0vous pouvez utiliser [0].concat(arr)ou avec une syntaxe étendue [0, ...arr](à la place de 'arr')
Simon_Weaver
existe-t-il un moyen d'exclure les valeurs nulles dans la voie 1?
bonbon.langes
22

Pour ce faire, étendez le type de tableau:

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

Boosté d' ici (par John Resig)

inkedmn
la source
20

Une solution simple pour trouver la valeur minimale sur un Arraydes éléments est d'utiliser la Arrayfonction prototype reduce:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min ? val : min, A[0]); // returns -9

ou en utilisant la fonction Math.Min () intégrée de JavaScript (merci @Tenflex):

A.reduce((min,val) => Math.min(min,val), A[0]);

Cette valeur est définie minsur A[0], puis vérifie A[1]...A[n]si elle est strictement inférieure à la valeur actuelle min. Si A[i] < minalors minest mis à jour vers A[i]. Lorsque tous les éléments du tableau ont été traités, minest renvoyé comme résultat.

EDIT : Inclure la position de la valeur minimale:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min._min ? {_min: val, _idx: min._curr, _curr: min._curr + 1} : {_min: min._min, _idx: min._idx, _curr: min._curr + 1}, {_min: A[0], _idx: 0, _curr: 0}); // returns { _min: -9, _idx: 2, _curr: 6 }
Nicolas Lykke Iversen
la source
3
A. réduire ((min, val) => Math.min (min, val), A [0]); encore plus court
Tenflex
En bonus, comment avoir non seulement la minvaleur retournée mais aussi sa position dans le tableau?
stevek
@meshfields - J'ai mis à jour la réponse.
Nicolas Lykke Iversen
15

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 devrait être Math.min.apply( Math, array )ou Math.min.apply( null, array ). Alors, quel contexte devrait être utilisé, Mathou null?

Lors du passage en nulltant que contexte à apply, le contexte sera par défaut l'objet global (l' windowobjet dans le cas des navigateurs). Passer l' Mathobjet en tant que contexte serait la bonne solution, mais cela ne fera pas de mal non nullplus. Voici un exemple où nullpourrait causer des problèmes, lors de la décoration de la Math.maxfonction:

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

Ce qui précède lèvera une exception car this.foosera évalué comme window.foo, ce qui est undefined. Si nous remplaçons nullpar Math, les choses fonctionneront comme prévu et la chaîne "foo" sera imprimée à l'écran (j'ai testé cela en utilisant Mozilla Rhino ).

Vous pouvez à peu près supposer que personne n'a décoré Math.maxainsi, le passage nullfonctionnera sans problème.

Ionuț G. Stan
la source
2
Point pris. Mais pourquoi décorerait-on Foo.staticMethodet ferait-il référence this? Ne serait-ce pas une erreur dans la conception du décorateur? (à moins bien sûr qu'ils voulaient faire référence à la portée globale et qu'ils souhaitent rester indépendants du moteur JavaScript utilisé, par exemple Rhino).
Roatin Marth
1
La spécification est explicite sur les fonctions spécifiées qui doivent se référer à "la valeur this " (en effet, cette phrase apparaît 125 fois dans la spécification). Math.max, implémenté par spécification, n'utilise pas this. Si quelqu'un remplace Math.maxtel qu'il l'utilise this, alors il a rendu son comportement contraire aux spécifications et vous devez lui lancer 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 ait troqué Math.maxet Math.minpour le lulz.
Mark Amery
15

Une autre façon de le faire:

var arrayMax = Function.prototype.apply.bind(Math.max, null);

Usage:

var max = arrayMax([2, 5, 1]);
sbr
la source
Quelqu'un peut-il expliquer comment cela fonctionne? C'est assez stupide. Ma compréhension est-elle correcte: arrayMax est une fonction et nous lions quelque chose à une propriété de son prototype? Qu'est-ce que c'est apply.bind et tous les prototypes l'ont-ils?
Sam
14

Méthodes alternatives


Les Math.minet Math.maxméthodes sont les deux opérations récursives qui sont ajoutés à la pile d'appel de moteur JS, et le plus probable accident pour un tableau qui contient un grand nombre d'articles
(plus de ~ 10⁷ articles, dépend du navigateur de l'utilisateur).

Math.max (... Array (1000000) .keys ());

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

Utilisez plutôt quelque chose comme ceci:

arr.reduce((max, val) => max > val ? max : val, arr[0])

Ou avec un meilleur temps d'exécution:

function maxValue(arr) {
  let max = arr[0];

  for (let val of arr) {
    if (val > max) {
      max = val;
    }
  }
  return max;
}

Ou pour obtenir à la fois Min et Max:

function getMinMax(arr) {
  return arr.reduce(({min, max}, v) => ({
    min: min < v ? min : v,
    max: max > v ? max : v,
  }), { min: arr[0], max: arr[0] });
}

Ou avec un temps d'exécution encore meilleur *:

function getMinMax(arr) {
  let min = arr[0];
  let max = arr[0];
  let i = arr.length;

  while (i--) {
    min = arr[i] < min ? arr[i] : min;
    max = arr[i] > max ? arr[i] : max;
  }
  return { min, max };
}

* Testé avec 1000000 articles:
Juste pour référence, le temps d'exécution de la 1ère fonction (sur ma machine) était de 15,84 ms par rapport à la 2e fonction avec seulement 4,32 ms.

Lior Elrom
la source
13

Cela peut convenir à vos besoins.

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
la source
vous devez initialiser votre v avec 'this [0]' au cas où aucun nombre ne
serait
Est comparercensé être appelé dans une portée spécifique? Parce que c'est comme ça this[index]qui fait référence à undefinedchaque fois.
Roatin Marth
Corrigé, j'oublie toujours la portée du niveau de fonction.
ChaosPandion
Oh maintenant, maintenant @Ionut G. Stan vous critiquera pour le même argument de "mauvais contexte" que lui, puisque votre comparateur par défaut ( Math.xxx) fonctionnera dans la portée globale ...
Roatin Marth
Cela peut être vrai, mais la nouvelle signature de fonction ne nécessite aucune portée car elle prend les 2 objets à comparer.
ChaosPandion
12

Je suis surpris que personne n'ait mentionné la fonction de réduction.

var arr = [1, 10, 5, 11, 2]

var b = arr.reduce(function(previous,current){ 
                      return previous > current ? previous:current
                   });

b => 11
arr => [1, 10, 5, 11, 2]
Stallion_V
la source
Attention: Reduce () est pris en charge par IE9, voir developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Paul Gobée
1
Je n'arrive pas à utiliser cela dans la version actuelle de Chromium.
PJSCopeland
9

Pour les grands tableaux (~ 10⁷ éléments), Math.minet Math.maxgénère une RangeError (taille maximale de la pile d'appels dépassée) dans node.js.

Pour les grands tableaux, une solution rapide et sale est:

Array.prototype.min = function() {
    var r = this[0];
    this.forEach(function(v,i,a){if (v<r) r=v;});
    return r;
};
Peter
la source
8

J'ai eu le même problème, j'avais besoin d'obtenir les valeurs minimum et maximum d'un tableau et, à ma grande surprise, il n'y avait pas de fonctions intégrées pour les tableaux. Après avoir beaucoup lu, j'ai décidé de tester moi-même les solutions "top 3":

  1. solution discrète: une boucle FOR pour vérifier chaque élément du tableau par rapport à la valeur max et / ou min actuelle;
  2. Solution APPLY: envoyer le tableau aux fonctions internes Math.max et / ou Math.min en utilisant apply (null, array);
  3. Solution REDUCE: récursion d'une vérification par rapport à chaque élément du tableau à l'aide de la fonction de réduction (fonction).

Le code de test était le suivant:

function GetMaxDISCRETE(A)
{   var MaxX=A[0];

    for (var X=0;X<A.length;X++)
        if (MaxX<A[X])
            MaxX=A[X];

    return MaxX;
}

function GetMaxAPPLY(A)
{   return Math.max.apply(null,A);
}

function GetMaxREDUCE(A)
{   return A.reduce(function(p,c)
    {   return p>c?p:c;
    });
}

Le tableau A était rempli de 100 000 nombres entiers aléatoires, chaque fonction a été exécutée 10 000 fois sur Mozilla Firefox 28.0 sur un bureau Intel Pentium 4 à 2,99 GHz avec Windows Vista. Les temps sont en secondes, récupérés par la fonction performance.now (). Les résultats étaient les suivants, avec 3 chiffres fractionnaires et l'écart type:

  1. Solution discrète: moyenne = 0,161 s, sd = 0,078
  2. APPLIQUER la solution: moyenne = 3,571 s, sd = 0,487
  3. RÉDUIRE la solution: moyenne = 0,350s, sd = 0,044

La solution REDUCE était 117% plus lente que la solution discrète. La solution APPLY était la pire, 2 118% plus lente que la solution discrète. En outre, comme Peter l'a observé, cela ne fonctionne pas pour les grands tableaux (environ plus de 1 000 000 d'éléments).

Aussi, pour terminer les tests, j'ai testé ce code discret étendu:

var MaxX=A[0],MinX=A[0];

for (var X=0;X<A.length;X++)
{   if (MaxX<A[X])
        MaxX=A[X];
    if (MinX>A[X])
        MinX=A[X];
}

Le timing: moyenne = 0,218 s, sd = 0,094

Ainsi, elle est 35% plus lente que la solution discrète simple, mais elle récupère à la fois les valeurs maximale et minimale à la fois (toute autre solution prendrait au moins deux fois celle pour les récupérer). Une fois que l'OP avait besoin des deux valeurs, la solution discrète serait le meilleur choix (même si deux fonctions distinctes, une pour le calcul du maximum et une autre pour le calcul du minimum, elles surperformaient la deuxième meilleure, la solution REDUCE).

Cyberknight
la source
8

Vous pouvez utiliser la fonction suivante n'importe où dans votre projet:

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

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

Et puis vous pouvez appeler les fonctions passant le tableau:

var myArray = [1,2,3,4,5,6,7];
var maximo = getMax(myArray); //return the highest number
Max Cabrera
la source
8

Le code suivant fonctionne pour moi:

var valueList = [10,4,17,9,3];
var maxValue = valueList.reduce(function(a, b) { return Math.max(a, b); });
var minValue = valueList.reduce(function(a, b) { return Math.min(a, b); });
jaydip jadhav
la source
7

Parcourez, gardez une trace au fur et à mesure.

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

Cela laissera min / max null s'il n'y a aucun élément dans le tableau. Fixera min et max en une seule passe si le tableau a des éléments.

Vous pouvez également étendre Array avec une rangeméthode utilisant ce qui précède pour permettre la réutilisation et améliorer la lisibilité. Voir un violon fonctionnel sur http://jsfiddle.net/9C9fU/

Array.prototype.range = function() {

    var min = null,
        max = null,
        i, len;

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

    return { min: min, max: max }
};

Utilisé comme

var arr = [3, 9, 22, -7, 44, 18, 7, 9, 15];

var range = arr.range();

console.log(range.min);
console.log(range.max);
tvanfosson
la source
@JordanDillonChapian Je serais d'accord, mais il serait trivial d'étendre cela à une rangefonction qui serait le meilleur moyen d'obtenir à la fois le min et le max à la fois IMO - comme je l'ai fait avec une mise à jour de ma réponse.
tvanfosson
6

J'ai pensé partager ma solution simple et facile à comprendre.

Pour le min:

var arr = [3, 4, 12, 1, 0, 5];
var min = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] < min) {
    min = arr[k];
  }
}
console.log("Min is: " + min);

Et pour le max:

var arr = [3, 4, 12, 1, 0, 5];
var max = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] > max) {
    max = arr[k];
  }
}
console.log("Max is: " + max);

Ionut Necula
la source
Merci. J'ai changé ma réponse.
Ionut Necula
L'itération est toujours erronée (accès aux propriétés inexistantes).
Bergi
Ce qui ne va pas, je ne vois rien de mal. Pouvez-vous donner un exemple s'il vous plaît?
Ionut Necula
1
Modifié en conséquence maintenant. J'espère que je vous ai bien compris.
Ionut Necula
5

Des trucs simples, vraiment.

var arr = [10,20,30,40];
arr.max = function() { return  Math.max.apply(Math, this); }; //attach max funct
arr.min = function() { return  Math.min.apply(Math, this); }; //attach min funct

alert("min: " + arr.min() + " max: " + arr.max());
Brian
la source
5

Voici une façon d'obtenir la valeur maximale d'un tableau d'objets. Créez une copie (avec tranche), puis triez la copie dans l'ordre décroissant et récupérez le premier élément.

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

maxsort = myArray.slice(0).sort(function(a, b) { return b.ID - a.ID })[0].ID; 
Ben
la source
5

Utilisation de Math.max()ouMath.min()

Math.max(10, 20);   //  20
Math.min(-10, -20); // -20

La fonction suivante utilise Function.prototype.apply()pour rechercher l'élément maximum dans un tableau numérique. getMaxOfArray([1, 2, 3])est équivalent à Math.max(1, 2, 3), mais vous pouvez l'utiliser getMaxOfArray()sur des tableaux construits par programmation de n'importe quelle taille.

function getMaxOfArray(numArray) {
  return Math.max.apply(null, numArray);
}

Ou avec le nouvel opérateur d'étalement, obtenir le maximum d'un tableau devient beaucoup plus facile.

var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1
shilovk
la source
5

Outre l'utilisation des fonctions mathématiques max et min, une autre fonction à utiliser est la fonction intégrée de sort (): c'est parti

const nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let max = nums[0]
let min = nums[nums.length -1]
Pedro JR
la source
4

La solution de ChaosPandion fonctionne si vous utilisez protoype. Sinon, considérez ceci:

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

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

Ce qui précède renverra NaN si une valeur de tableau n'est pas un entier, vous devez donc créer des fonctionnalités pour éviter cela. Sinon, cela fonctionnera.

geai
la source
jeerose, pourquoi avez-vous (Math, ceci) comme agrément alors que Roatin Marth n'a que (null, ceci)?
HankH
@HankH: voir ma réponse à votre commentaire dans un commentaire à ma propre réponse.
Roatin Marth
1
Je ne comprends pas ce que vous entendez par "la solution de ChaosPandion fonctionne si vous utilisez protoype". En quoi votre solution est-elle différente, sauf que vous utilisez l' Mathobjet comme contexte?
Ionuț G. Stan
Désolé, je voulais dire que si vous étendez le prototype, le vôtre fonctionnera. Mes excuses.
jay
Alors, quel est le meilleur, jeerose ou ChaosPandion?
HankH
3

Si vous utilisez la bibliothèque sugar.js , vous pouvez écrire arr.min () et arr.max () comme vous le suggérez. Vous pouvez également obtenir des valeurs min et max à partir de tableaux non numériques.

min (map, all = false) Renvoie l'élément du tableau avec la valeur la plus basse. map peut être une fonction mappant la valeur à vérifier ou une chaîne faisant office de raccourci. Si tout est vrai, retournera toutes les valeurs min dans un tableau.

max (map, all = false) Renvoie l'élément du tableau avec la plus grande valeur. map peut être une fonction mappant la valeur à vérifier ou une chaîne faisant office de raccourci. Si tout est vrai, renverra toutes les valeurs maximales dans un tableau.

Exemples:

[1,2,3].min() == 1
['fee','fo','fum'].min('length') == "fo"
['fee','fo','fum'].min('length', true) == ["fo"]
['fee','fo','fum'].min(function(n) { return n.length; }); == "fo"
[{a:3,a:2}].min(function(n) { return n['a']; }) == {"a":2}
['fee','fo','fum'].max('length', true) == ["fee","fum"]

Des bibliothèques comme Lo-Dash et underscore.js fournissent également des fonctions min et max puissantes similaires:

Exemple de Lo-Dash:

_.max([4, 2, 8, 6]) == 8
var characters = [
  { 'name': 'barney', 'age': 36 },
  { 'name': 'fred',   'age': 40 }
];
_.max(characters, function(chr) { return chr.age; }) == { 'name': 'fred', 'age': 40 }
andersh
la source
3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
UA_
la source
2
Cette solution a déjà été fournie par plusieurs autres répondeurs à cette question. Qu'ajoute ta réponse?
Nick
3

Essayer

let max= a=> a.reduce((m,x)=> m>x ? m:x);
let min= a=> a.reduce((m,x)=> m<x ? m:x);

Pour Math.min / max (+ appliquer), nous obtenons une erreur:

Dépassement de la taille maximale de la pile d'appels (Chrome 74.0.3729.131)

Kamil Kiełczewski
la source