Trouver l’index de l’object dans le tableau avec la valeur la plus élevée dans la propriété

J’ai un tableau avec des objects:

var articles = []; var article = {}; Simple loop that iterates x times { article.text = "foobar"; article.color = "red"; article.number = 5; articles.push(article); } 

Je ne sais pas combien d’objects il y aura dans mon tableau, mais ils auront tous des valeurs différentes pour leurs propriétés, je viens de donner quelques exemples ici.

Question

Je dois trouver un moyen de parcourir tous ces objects et de récupérer l’index de l’object qui a la valeur la plus élevée dans article.number. Comment puis-je atteindre cet objective? Je ne peux utiliser que javascript, jQuery, etc., pas d’autres langues.

J’imagine que cela impliquera l’utilisation de $ .grep et de Math.max mais je suis coincé, je n’ai jamais travaillé avec $ .grep auparavant.

En bref:

 var highestNumber = index of object where article.number is highest 

Math.max() , $.grep et $.map sont quelques-unes, mais une méthode facile et lisible qui devrait être compréhensible consiste simplement à itérer l’object et à vérifier si la valeur est supérieure à une variable, si c’est le cas, définissez la variable sur le nombre le plus élevé:

 var highest = 0; $.each(articles, function(key, article) { if (article.number > highest) highest = article.number; }); // highest now contains the highest number 

Underscore.js est une merveilleuse bibliothèque qui fournit des opérations fonctionnelles pour les collections. Une solution en soulignement:

 var maxObj = _.max(array, function (obj) { return obj.number; }); var maxIndex = array.indexOf(maxObj); 

Bien que cet exemple soit assez simple, les opérations évoluent bien. Supposons que vous vouliez additionner la propriété number de chaque object du tableau dont le texte était égal à Foo et la couleur égale à red :

 var customSum = _.chain(array) .where({ text: "Foo", color: "red" }) .map(function(obj) { return obj.number; }) .reduce(function(memo, num) { return memo + num; }, 0) .value(); 

Si la performance vous intéresse, une bibliothèque externe est certainement la solution. Les bibliothèques externes peuvent fournir une quantité considérable d’optimisations qu’il serait difficile de faire correspondre à votre propre code. Cela dit, pour traiter un petit nombre d’éléments (moins de plusieurs milliers), il n’y aura pas de différence de performance appréciable entre les réponses affichées ici. Ne vous laissez pas berner par l’parsing comparative et utilisez la réponse la plus compréhensible pour vous.

JSFiddle

Que diriez-vous:

 articleWithMaxNumber = articles.slice(0).sort( function(x, y) { return y.number - x.number })[0] 

et si vous avez besoin d’un index:

 index = articles.indexOf(articleWithMaxNumber) 

Et pour ceux qui pensent que le sorting peut s’avérer excessif pour obtenir la valeur maximale:

 articleWithMaxNumber = articles.reduce(function(max, x) { return x.number > max.number ? x : max; }) 

Et voici une approche générique pour trouver un maximum d’applications fonctionnelles à l’aide de map-reduction:

 function maxBy(array, fn) { return array.map(function(x) { return [x, fn(x)] }).reduce(function(max, x) { return x[1] > max[1] ? x : max; })[0] } articleWithMaxNumber = maxBy(articles, function(x) { return x.number }) 

Certaines personnes ont dit craindre que la méthode de sort soit “lente” par rapport à la méthode itérative. Voici un violon qui utilise les deux méthodes pour traiter un tableau de 50000 éléments . La méthode de sort est “plus lente” d’environ 50 millisecondes sur ma machine. Cela dépend de l’application, mais dans la plupart des cas, ce n’est pas quelque chose d’intéressant.

 var articles = []; var len = 50000; while (len--) { var article = {}; article.text = "foobar"; article.color = "red"; article.number = Math.random(); articles.push(article); } d = performance.now(); max1 = articles.slice(0).sort( function(x, y) { return y.number - x.number })[0] time1 = performance.now() - d d = performance.now(); max2 = articles.reduce(function(max, x) { return x.number > max.number ? x : max; }) time2 = performance.now() - d document.body.innerHTML = [time1, time2].join("
")

Voici une solution possible

Javascript

 var articles = [], howMany = 5, i = 0, article, highest; while (i < howMany) { article = {}; article.text = "foobar"; article.color = "red"; article.number = i; articles.push(article); i += 1; } console.log(articles); hownMany = articles.length; i = 0; while (i < howMany) { if (typeof highest !== "number" || articles[i].number > highest) { highest = i; } i += 1; } console.log(articles[highest]); 

Sur jsfiddle

Voici le test de performance pour les méthodes actuelles, n’hésitez pas à append des réponses.

Je n’utiliserai rien comme Math ou jQuery, il suffit de sortinger le tableau résultant et de supprimer le dernier élément:

 var sortArticles = function (a, b) { return ( a.number - b.number ); // should have some type checks ? inverse order: swap a/b } articles.sort(sortArticles); highestArticle = articles.pop(); // or articles[array.length-1]; // take care if srticles.length = null ! 

Tant que vous n’avez pas une tonne d’articles dans votre mémoire, c’est le moyen le plus rapide.

 array[array.map((o)=>o.number).indexOf(Math.max(...array.map((o)=>o.number)))] 

Moyens get élément avec index (i) où (i) est l’index du plus grand nombre.

 items => items .reduce( ( highest, item, index ) => item > highest.item ? { item, index } : highest , { item: Number.NEGATIVE_INFINITY } ) .index