Recherche de la valeur maximale d'un attribut dans un tableau d'objets

413

Je cherche un moyen très rapide, propre et efficace pour obtenir la valeur maximale "y" dans la tranche JSON suivante:

[
  {
    "x": "8/11/2009",
    "y": 0.026572007
  },
  {
    "x": "8/12/2009",
    "y": 0.025057454
  },
  {
    "x": "8/13/2009",
    "y": 0.024530916
  },
  {
    "x": "8/14/2009",
    "y": 0.031004457
  }
]

Une boucle for est-elle la seule façon de procéder? Je tiens à utiliser en quelque sorte Math.max.

Rio
la source
4
Comment retourneriez-vous l'objet et pas seulement la valeur d'attr min trouvée?
Mike Lyons
1
Pour mon propre bénéfice, j'ai effectué quelques tests de perf sur ce sujet. jsperf.com/finding-the-max-value-an-array-of-objects
Andy Polhill
1
JSBin des solutions jsbin.com/pagamujuge/edit?html,js,console
Andy Polhill

Réponses:

742

Pour trouver la yvaleur maximale des objets dans array:

Math.max.apply(Math, array.map(function(o) { return o.y; }))
tobyodavies
la source
48
Pourriez-vous développer cette réponse pour montrer comment renvoyer l'objet dans lequel la valeur maximale a été trouvée? Ce serait très utile, merci!
Mike Lyons
19
Voici le violon! j'espère que cela aidera quelqu'un jsfiddle.net/45c5r246
mili
24
@MikeLyons si vous vous souciez toujours d'obtenir l'objet réel: jsfiddle.net/45c5r246/34
tobyodavies
11
Veuillez expliquer votre réponse!
John William Domingo
12
FWIW ma compréhension est que lorsque vous appelez apply sur une fonction, il exécute la fonction avec une valeur spécifiée pour thiset une série d'arguments spécifiés sous forme de tableau. L'astuce est qu'appliquer transforme le tableau en une série d'arguments de fonction réels. Donc dans ce cas il appelle finalement Math.max(0.0265, 0.0250, 0.024, 0.031)avec thisla fonction exécutée Math. Je ne vois pas pourquoi cela devrait être Mathfranchement, je ne pense pas que la fonction nécessite un valide this. Oh et voici une explication appropriée: stackoverflow.com/questions/21255138/…
Daniel C
263

Rechercher l'objet dont la propriété "Y" a la plus grande valeur dans un tableau d'objets

Une façon serait d'utiliser la réduction de tableau ..

const max = data.reduce(function(prev, current) {
    return (prev.y > current.y) ? prev : current
}) //returns object

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce http://caniuse.com/#search=reduce (IE9 et supérieur)

Si vous n'avez pas besoin de prendre en charge IE (uniquement Edge), ou si vous pouvez utiliser un précompilateur tel que Babel, vous pouvez utiliser la syntaxe la plus laconique.

const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current)
Andy Polhill
la source
7
C'est une bonne réponse, cependant, vous souhaitez passer une valeur initiale ou vous obtiendrez une erreur au cas où le tableau de données serait vide. c'est-à-dire pour un index d'auto-incrémentation d'objets. const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current, 1)
juliangonzalez
2
Vous soulevez un bon point, je choisirais probablement nullplus de 1.
Andy Polhill
25
Notez que cela renvoie l'objet qui avait la valeur max et non la valeur max de l'objet. Cela peut ou non être ce que vous voulez. Dans mon cas, c'était ce que je voulais. +1
John
1
Bonne réponse complémentaire!
Legends
Excellente réponse! Au début, j'ai hésité à cause de la réduction, mais nous allons quand même avoir besoin de répéter, alors pourquoi pas?
shapiro yaacov
147

ES6 propre et simple (Babel)

const maxValueOfY = Math.max(...arrayToSearchIn.map(o => o.y), 0);

Le deuxième paramètre doit garantir une valeur par défaut si arrayToSearchInest vide.

Vitaliy Kotov
la source
8
il est également bon de savoir qu'il retourne -Infinity(une valeur véridique ) pour un tableau vide
icl7126
1
Ceci est pris en charge dans la plupart des navigateurs modernes sans Babel maintenant.
Eugene Kulabuhov
20
comme il revient -Infinitypour un tableau vide, vous pouvez passer une valeur initiale Math.max(...state.allProjects.map(o => o.id), 1);
juliangonzalez
5
Cela devrait être la réponse acceptée maintenant ... certainement l'approche la plus laconique.
nickb
1
pour gérer la casse des valeurs moins, changez 0en arrayToSearchIn[0].y. Comparaison de la complexité temporelle: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski
43

Comparaison des ONELINERS d' arbre qui gèrent le cas des nombres négatifs (entrée dans le atableau):

var maxA = a.reduce((a,b)=>a.y>b.y?a:b).y;  // 30 chars time complexity:  O(n)

var maxB = a.sort((a,b)=>b.y-a.y)[0].y;     // 27 chars time complexity:  O(nlogn)

var maxC = Math.max(...a.map(o=>o.y));      // 26 chars time complexity: >O(2n)

exemple modifiable ici . Idées de: maxA , maxB et maxC (l'effet secondaire de maxB est que le tableau aest modifié parce qu'il sortest en place).

Pour les baies plus grandes, l' Math.max...exception lancera: la taille maximale de la pile d'appels est dépassée (Chrome 76.0.3809, Safari 12.1.2, date 2019-09-13)

Kamil Kiełczewski
la source
2
Des méthodes très intelligentes pour accomplir la tâche. Nice
TetraDev
Désolé, il a voté par erreur et n'a pas pu être annulé sans modifier votre question car trop de temps s'est écoulé.
Günter Zöchbauer
Merci grande analyse.
d337
merci pour cette ventilation des options disponibles et les différences entre les approches.
FistOfFury
une chose à souligner est que l'option B facilite beaucoup l'obtention de l'objet entier avec la yvaleur maximale en laissant le .yà la fin.
FistOfFury
24

Je voudrais expliquer la réponse concise acceptée étape par étape:

var objects = [{ x: 3 }, { x: 1 }, { x: 2 }];

// array.map lets you extract an array of attribute values
var xValues = objects.map(function(o) { return o.x; });
// es6
xValues = Array.from(objects, o => o.x);

// function.apply lets you expand an array argument as individual arguments
// So the following is equivalent to Math.max(3, 1, 2)
// The first argument is "this" but since Math.max doesn't need it, null is fine
var xMax = Math.max.apply(null, xValues);
// es6
xMax = Math.max(...xValues);

// Finally, to find the object that has the maximum x value (note that result is array):
var maxXObjects = objects.filter(function(o) { return o.x === xMax; });

// Altogether
xMax = Math.max.apply(null, objects.map(function(o) { return o.x; }));
var maxXObject = objects.filter(function(o) { return o.x === xMax; })[0];
// es6
xMax = Math.max(...Array.from(objects, o => o.x));
maxXObject = objects.find(o => o.x === xMax);


document.write('<p>objects: ' + JSON.stringify(objects) + '</p>');
document.write('<p>xValues: ' + JSON.stringify(xValues) + '</p>');
document.write('<p>xMax: ' + JSON.stringify(xMax) + '</p>');
document.write('<p>maxXObjects: ' + JSON.stringify(maxXObjects) + '</p>');
document.write('<p>maxXObject: ' + JSON.stringify(maxXObject) + '</p>');

Plus d'informations:

congusbongus
la source
Grande explication! Il pourrait être un peu plus facile à lire s'il n'était pas dans les commentaires de code, mais quand même - excellent travail
Martin
23

Eh bien, vous devez d'abord analyser la chaîne JSON, afin que vous puissiez facilement accéder à ses membres:

var arr = $.parseJSON(str);

Utilisez la mapméthode pour extraire les valeurs:

arr = $.map(arr, function(o){ return o.y; });

Ensuite, vous pouvez utiliser le tableau dans la maxméthode:

var highest = Math.max.apply(this,arr);

Ou en monoplace:

var highest = Math.max.apply(this,$.map($.parseJSON(str), function(o){ return o.y; }));
Guffa
la source
15
Ce n'est pas tagué avecjQuery
Robin van Baalen
1
@RobinvanBaalen: Oui, vous avez raison. Il est cependant étiqueté avec JSON mais la réponse acceptée l'ignore, et tobyodavies l'a également retiré du sujet de la question ... Peut-être devrais-je ajouter jquery à la question ...;)
Guffa
8
Peu importe si @tobyodavies a ignoré le fait qu'il a été balisé json- il n'utilise pas de bibliothèque javascript externe dans sa réponse :)
Robin van Baalen
12
var data = [
  { 'name': 'Vins', 'age': 27 },
  { 'name': 'Jan', 'age': 38 },
  { 'name': 'Alex', 'age': 80 },
  { 'name': 'Carl', 'age': 25 },
  { 'name': 'Digi', 'age': 40 }
];
var max = data.reduce(function (prev, current) {
   return (prev.age > current.age) ? prev : current
});
//output = {'name': 'Alex', 'age': 80}
Vin S
la source
2
En quoi cela diffère-t-il de la réponse de @ AndyPolhill?
Lewis
7

si vous (ou quelqu'un ici) êtes libre d'utiliser la lodashbibliothèque d'utilitaires, elle a une fonction maxBy qui serait très pratique dans votre cas.

vous pouvez donc utiliser comme tel:

_.maxBy(jsonSlice, 'y');
kmonsoor
la source
6

Ou une sorte simple! Garder les choses réelles :)

array.sort((a,b)=>a.y<b.y)[0].y
Ooki Koi
la source
Belle idée +1 (code le plus court), mais il y a un petit bug - changez a.y<a.ypour b.y-a.y. Comparaison de la complexité du temps ici: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski
2
Trouver le max est O (n). C'est O (nlogn). Écrire du code simple est bon tant que l'efficacité n'est pas sacrifiée.
Wildhammer
@Wildhammer - en fait, la micro-optimisation en vaut la peine lorsque vous avez la preuve que vous optimisez un goulot d'étranglement. . Dans la plupart des cas, le code simple est un meilleur choix que le code à haute efficacité.
Kamil Kiełczewski
@ KamilKiełczewski Les deux comparaisons de tableaux de cet article ont la même complexité temporelle, la différence réside dans leur coefficient. Par exemple, l'un prend n unités de temps pour trouver la solution tandis que l'autre est 7n. Dans la théorie de la complexité temporelle, les deux sont O (n). Ce dont nous parlons dans le problème de la recherche de max est la comparaison de O (n) avec O (n logn). Maintenant, si vous pouvez garantir que n ne dépasse pas 10, vous pouvez utiliser votre solution, sinon l'algorithme O (n) est toujours gagnant et les performances (expérience utilisateur) sont toujours antérieures à l'expérience développeur (demandez aux gens de l'industrie, ils vous le disent!) .
Wildhammer
@Wildhammer nope - même si votre tableau a n = 10000 éléments, l'utilisateur ne verra pas la différence ICI . L'optimisation des performances n'est bonne que pour les goulots d'étranglement des applications (par exemple, vous devez traiter de grandes baies) - mais dans la plupart des cas, une focalisation sur les performances est une mauvaise approche et une perte de temps (= argent). C'est une erreur d'approche de code bien connue - en savoir plus: "micro-optimisation"
Kamil Kiełczewski
3

Chaque tableau et obtenez la valeur maximale avec Math.

data.reduce((max, b) => Math.max(max, b.costo), data[0].costo);
Diego Santa Cruz Mendezú
la source
2

Voici la solution la plus courte (One Liner) ES6 :

Math.max(...values.map(o => o.y));
Subodh Singh
la source
1
var max = 0;                
jQuery.map(arr, function (obj) {
  if (obj.attr > max)
    max = obj.attr;
});
Mephisto07
la source
1
Here is very simple way to go:

Your DataSet.

let numberArray = [
  {
    "x": "8/11/2009",
    "y": 0.026572007
  },
  {
    "x": "8/12/2009",
    "y": 0.025057454
  },
  {
    "x": "8/13/2009",
    "y": 0.024530916
  },
  {
    "x": "8/14/2009",
    "y": 0.031004457
  }
]

1. First create Array, containing all the value of Y
let result = numberArray.map((y) => y)
console.log(result) >> [0.026572007,0.025057454,0.024530916,0.031004457]

2. let maxValue = Math.max.apply(null, result)
console.log(maxvalue) >> 0.031004457
Pushp Singh
la source