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.


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

Antworten:


739

So finden Sie den Maximalwert yder Objekte in array:

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

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)

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.


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


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

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:


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}

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

5

Oder eine einfache Sorte! Halte es real :)

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

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


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

1

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

Math.max(...values.map(o => o.y));
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.