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.


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

Réponses:


742

Pour trouver la yvaleur maximale des objets dans array:

Math.max.apply(Math, array.map(function(o) { return o.y; }))

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)

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.


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)


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:


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

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}

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

6

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

array.sort((a,b)=>a.y<b.y)[0].y

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


2

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

Math.max(...values.map(o => o.y));

1
var max = 0;                
jQuery.map(arr, function (obj) {
  if (obj.attr > max)
    max = obj.attr;
});


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.