Ermitteln des Maximalwerts eines Attributs in einem Array von Objekten

413

Ich suche nach einer wirklich schnellen, sauberen und effizienten Methode, um den maximalen "y" -Wert im folgenden JSON-Slice zu erhalten:

[
  {
    "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
  }
]

Ist eine for-Schleife der einzige Weg, dies zu tun? Ich bin daran interessiert, es irgendwie zu benutzen Math.max.

Rio
quelle
4
Wie würden Sie das Objekt zurückgeben und nicht nur den gefundenen Mindestwert?
Mike Lyons
1
Zu meinem eigenen Vorteil habe ich einige schnelle Perfektionstests durchgeführt. jsperf.com/finding-the-max-value-an-array-of-objects
Andy Polhill
1
JSBin der Lösungen jsbin.com/pagamujuge/edit?html,js,console
Andy Polhill

Antworten:

739

So finden Sie den Maximalwert yder Objekte in array:

Math.max.apply(Math, array.map(function(o) { return o.y; }))
tobyodavies
quelle
47
Könnten Sie diese Antwort erweitern, um zu zeigen, wie das Objekt zurückgegeben wird, in dem der Maximalwert gefunden wurde? Das wäre sehr hilfreich, danke!
Mike Lyons
19
Hier ist die Geige! hoffen , dies wird dazu beitragen, jemand jsfiddle.net/45c5r246
mili
24
@ MikeLyons, wenn Sie immer noch daran interessiert sind, das eigentliche Objekt zu erhalten: jsfiddle.net/45c5r246/34
tobyodavies
11
Bitte erläutern Sie Ihre Antwort!
John William Domingo
12
FWIW Ich verstehe, wenn Sie Apply für eine Funktion aufrufen, wird die Funktion mit einem angegebenen Wert für thisund einer Reihe von Argumenten ausgeführt, die als Array angegeben sind. Der Trick besteht darin, dass apply das Array in eine Reihe von tatsächlichen Funktionsargumenten umwandelt. In diesem Fall ruft es also schließlich Math.max(0.0265, 0.0250, 0.024, 0.031)mit der thisausgeführten Funktion auf Math. Ich kann nicht verstehen, warum es Mathehrlich gesagt sein sollte, ich glaube nicht, dass die Funktion eine gültige erfordert this. Oh und hier ist eine richtige Erklärung: stackoverflow.com/questions/21255138/…
Daniel C
262

Suchen Sie das Objekt, dessen Eigenschaft "Y" den größten Wert in einem Array von Objekten hat

Eine Möglichkeit wäre die Verwendung von Array Reduce.

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 und höher)

Wenn Sie den IE (nur Edge) nicht unterstützen müssen oder einen Pre-Compiler wie Babel verwenden können, können Sie die knappere Syntax verwenden.

const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current)
Andy Polhill
quelle
7
Dies ist eine gute Antwort. Sie möchten jedoch einen Anfangswert übergeben oder erhalten eine Fehlermeldung, falls das Datenarray leer ist. dh für einen Autoincrement-Index von Objekten. const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current, 1)
Juliangonzalez
2
Sie sprechen einen guten Punkt an, ich würde wahrscheinlich nullüber 1 wählen .
Andy Polhill
25
Beachten Sie, dass dies das Objekt zurückgibt, dessen Maximalwert nicht der Maximalwert des Objekts war. Dies kann sein oder nicht, was Sie wollen. In meinem Fall war es das, was ich wollte. +1
John
1
Gute ergänzende Antwort!
Legenden
Hervorragende Antwort! Zuerst habe ich wegen der Reduzierung gezögert, aber wir müssen trotzdem iterieren. Warum also nicht?
Shapiro Yaacov
146

sauber und einfach ES6 (Babel)

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

Der zweite Parameter sollte einen Standardwert sicherstellen, wenn er arrayToSearchInleer ist.

Vitaliy Kotov
quelle
8
Es ist auch gut zu wissen, dass es -Infinity(ein wahrer Wert) für ein leeres Array
zurückgibt
1
Dies wird jetzt in den meisten modernen Browsern ohne Babel unterstützt.
Eugene Kulabuhov
20
-Infinity Math.max(...state.allProjects.map(o => o.id), 1);
Wenn
5
Dies sollte jetzt die akzeptierte Antwort sein ... definitiv der knappere Ansatz.
Nickb
1
Um den Fall für Minuswerte zu behandeln, ändern Sie sich 0zu arrayToSearchIn[0].y. Zeitkomplexitätsvergleich: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski
40

Vergleich der Baum- ONELINER, die den Fall der Minuszahlen behandeln (Eingabe im aArray):

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)

bearbeitbares Beispiel hier . Ideen von: maxA , maxB und maxC (Nebeneffekt von maxB ist, dass das Array ageändert wird, weil es vorhanden sortist).

Bei größeren Arrays Math.max...wird die Ausnahme ausgelöst : Die maximale Größe des Aufrufstapels wurde überschritten (Chrome 76.0.3809, Safari 12.1.2, Datum 2019-09-13).

Kamil Kiełczewski
quelle
2
Sehr clevere Methoden, um die Aufgabe zu erfüllen. Nizza
TetraDev
Entschuldigung, versehentlich herabgestimmt und konnte nicht rückgängig gemacht werden, ohne Ihre Frage zu bearbeiten, da zu viel Zeit vergangen ist.
Günter Zöchbauer
Vielen Dank, tolle Analyse.
d337
Vielen Dank für diese Aufschlüsselung der verfügbaren Optionen und die Unterschiede zwischen den Ansätzen.
FistOfFury
Eine Sache, auf die hingewiesen werden muss, ist, dass Option B es viel einfacher macht, das gesamte Objekt mit dem yMaximalwert zu erhalten, indem das .yam Ende weggelassen wird.
FistOfFury
23

Nun, zuerst sollten Sie die JSON-Zeichenfolge analysieren, damit Sie leicht auf ihre Mitglieder zugreifen können:

var arr = $.parseJSON(str);

Verwenden Sie die mapMethode, um die Werte zu extrahieren:

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

Dann können Sie das Array in der maxMethode verwenden:

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

Oder als Einzeiler:

var highest = Math.max.apply(this,$.map($.parseJSON(str), function(o){ return o.y; }));
Guffa
quelle
15
Es ist nicht markiert mitjQuery
Robin van Baalen
1
@RobinvanBaalen: Ja, du hast recht. Es ist jedoch mit JSON markiert, aber die akzeptierte Antwort ignoriert dies und tobyodavies entfernte dies auch aus dem Thema der Frage ... Vielleicht sollte ich der Frage eine Abfrage hinzufügen ...;)
Guffa
8
Es macht nicht viel aus, wenn @tobyodavies die Tatsache ignoriert, dass es markiert wurde json- er verwendet keine externe Javascript-Bibliothek in seiner Antwort :)
Robin van Baalen
23

Ich möchte die knapp akzeptierte Antwort Schritt für Schritt erklären :

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

Weitere Informationen:

Congusbongus
quelle
Tolle Erklärung! Es könnte ein bisschen einfacher zu lesen sein, wenn es nicht in Code-Kommentaren wäre, aber immer noch - großartige Arbeit
Martin
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.
quelle
2
Wie unterscheidet sich das von der Antwort von @ AndyPolhill?
Lewis
7

Wenn Sie (oder jemand hier) die lodashDienstprogrammbibliothek verwenden können, verfügt sie über eine maxBy- Funktion, die in Ihrem Fall sehr praktisch wäre.

daher können Sie als solche verwenden:

_.maxBy(jsonSlice, 'y');
kmonsoor
quelle
5

Oder eine einfache Sorte! Halte es real :)

array.sort((a,b)=>a.y<b.y)[0].y
Ooki Koi
quelle
Gute Idee +1 (kürzester Code), aber es gibt einen kleinen Fehler - ändern Sie a.y<a.yzu b.y-a.y. Zeitkomplexitätsvergleich hier: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski
2
Das Maximum zu finden ist O (n). Dies ist O (nlogn). Das Schreiben von einfachem Code ist gut, solange die Effizienz nicht beeinträchtigt wird.
Wildhammer
@Wildhammer - eigentlich lohnt sich die Mikrooptimierung , wenn Sie Beweise dafür haben, dass Sie einen Engpass optimieren. . In den meisten Fällen ist der einfache Code die bessere Wahl als hocheffizienter Code.
Kamil Kiełczewski
@ KamilKiełczewski Beide Array-Vergleiche in diesem Artikel haben die gleiche zeitliche Komplexität, der Unterschied liegt in ihrem Koeffizienten. Zum Beispiel benötigt man n Zeiteinheiten, um die Lösung zu finden, während die andere 7n ist. In der Zeitkomplexitätstheorie sind beide O (n). Worüber wir beim Problem des Findens von max sprechen, ist der Vergleich von O (n) mit O (n logn). Wenn Sie jetzt garantieren können, dass n 10 nicht überschreitet, können Sie Ihre Lösung verwenden, andernfalls ist der O (n) -Algorithmus immer der Gewinner und die Leistung (Benutzererfahrung) liegt immer vor der Entwicklererfahrung (fragen Sie Branchenleute, sie sagen Ihnen das!). .
Wildhammer
@Wildhammer nein - selbst wenn Ihr Array n = 10000 Elemente hat, wird der Benutzer HIER keinen Unterschied sehen . Die Leistungsoptimierung eignet sich nur für App-Engpässe (z. B. wenn Sie große Arrays verarbeiten müssen). In den meisten Fällen ist ein Leistungsfokus jedoch ein falscher Ansatz und Zeit- (= Geld-) Verschwendung. Dies ist ein bekannter Code-Ansatz-Fehler - lesen Sie mehr: "
Mikrooptimierung
3

Jedes Array und erhalten maximalen Wert mit Math.

data.reduce((max, b) => Math.max(max, b.costo), data[0].costo);
Diego Santa Cruz Mendezú
quelle
1
var max = 0;                
jQuery.map(arr, function (obj) {
  if (obj.attr > max)
    max = obj.attr;
});
Mephisto07
quelle
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
quelle
1

Hier ist die kürzeste Lösung (One Liner) ES6 :

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