Menemukan nilai maksimal atribut dalam array objek

413

Saya mencari cara yang sangat cepat, bersih, dan efisien untuk mendapatkan nilai "y" maksimum dalam slice JSON berikut:

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

Apakah for-loop satu-satunya cara untuk melakukannya? Saya tertarik entah bagaimana menggunakan Math.max.

Rio
sumber
4
Bagaimana Anda mengembalikan objek dan bukan hanya nilai mintrtr yang ditemukan?
Mike Lyons
1
Untuk keuntungan saya sendiri, saya menjalankan beberapa tes perf cepat tentang ini. jsperf.com/finding-the-max-value-an-array-of-objects
Andy Polhill
1
JSBin dari solusi jsbin.com/pagamujuge/edit?html,js,console
Andy Polhill

Jawaban:

741

Untuk menemukan nilai maksimum yobjek di array:

Math.max.apply(Math, array.map(function(o) { return o.y; }))
tobyodavies
sumber
47
Bisakah Anda memperluas jawaban ini untuk menunjukkan cara mengembalikan objek tempat nilai maks ditemukan? Itu akan sangat membantu, terima kasih!
Mike Lyons
19
Ini biola! harap ini akan membantu seseorang jsfiddle.net/45c5r246
mili
24
@MikeLyons jika Anda masih ingin mendapatkan objek yang sebenarnya: jsfiddle.net/45c5r246/34
tobyodavies
11
Tolong jelaskan jawaban Anda!
John William Domingo
12
FWIW pemahaman saya adalah ketika Anda memanggil berlaku pada fungsi itu menjalankan fungsi dengan nilai yang ditentukan untuk thisdan serangkaian argumen yang ditentukan sebagai array. Kuncinya adalah bahwa berlaku mengubah array menjadi serangkaian argumen fungsi aktual. Jadi dalam hal ini akhirnya panggilan Math.max(0.0265, 0.0250, 0.024, 0.031)dengan thisfungsi yang dijalankan Math. Saya tidak bisa melihat mengapa itu harus Mathterus terang, saya tidak berpikir fungsi ini memerlukan valid this. Oh dan inilah penjelasan yang tepat: stackoverflow.com/questions/21255138/…
Daniel C
263

Temukan objek yang propertinya "Y" memiliki nilai terbesar dalam array objek

Salah satu cara adalah dengan menggunakan pengurangan Array ..

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 ke atas)

Jika Anda tidak perlu mendukung IE (hanya Edge), atau dapat menggunakan pra-kompiler seperti Babel Anda bisa menggunakan sintaks yang lebih singkat.

const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current)
Andy Polhill
sumber
7
Ini adalah jawaban yang baik, namun, Anda ingin memberikan nilai awal atau Anda akan mendapatkan kesalahan jika array data kosong. yaitu untuk indeks objek autoincrement. const max = data.reduce((prev, current) => (prev.y > current.y) ? prev : current, 1)
juliangonzalez
2
Anda mendapatkan poin yang bagus, saya mungkin akan memilih nulllebih dari 1.
Andy Polhill
25
Perhatikan bahwa ini mengembalikan objek yang memiliki nilai maks, bukan nilai maks dari objek. Ini mungkin atau mungkin bukan yang Anda inginkan. Dalam kasus saya, itulah yang saya inginkan. +1
John
1
Jawaban komplementer yang bagus!
Legenda
Jawaban yang sangat bagus! Pada awalnya, saya ragu-ragu karena pengurangan itu, tapi bagaimanapun juga kita perlu mengulang, jadi mengapa tidak?
shapiro yaacov
147

ES6 bersih dan sederhana (Babel)

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

Parameter kedua harus memastikan nilai default jika arrayToSearchInkosong.

Vitaliy Kotov
sumber
8
juga baik itu untuk mengetahui bahwa ia mengembalikan -Infinity(a truthy nilai) untuk array kosong
icl7126
1
Ini didukung di sebagian besar browser modern tanpa Babel sekarang.
Eugene Kulabuhov
20
saat kembali -Infinityuntuk array kosong, Anda bisa memberikan nilai awal Math.max(...state.allProjects.map(o => o.id), 1);
juliangonzalez
5
Ini harus menjadi jawaban yang diterima sekarang ... pasti pendekatan yang lebih singkat.
julukan
1
untuk menangani case untuk nilai minus berubah 0menjadi arrayToSearchIn[0].y. Perbandingan kompleksitas waktu: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski
42

Perbandingan ONELINER pohon yang menangani case angka minus (input in 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)

contoh yang dapat diedit di sini . Gagasan dari: maxA , maxB dan maxC (efek samping dari maxB adalah array adiubah karena sortada di tempat).

Untuk array yang lebih besar Math.max...pengecualian lemparan akan terlampaui: Ukuran tumpukan panggilan maksimum terlampaui (Chrome 76.0.3809, Safari 12.1.2, tanggal 2019-09-13)

Kamil Kiełczewski
sumber
2
Metode yang sangat pintar untuk menyelesaikan tugas. Nice
TetraDev
Maaf, dibatalkan karena kesalahan dan tidak dapat diurungkan tanpa mengedit pertanyaan Anda karena terlalu banyak waktu berlalu.
Günter Zöchbauer
Terima kasih analisis yang bagus.
d337
terima kasih atas uraian opsi yang tersedia dan perbedaan antar pendekatan.
FistOfFury
satu hal yang perlu diperhatikan adalah opsi B membuatnya lebih mudah untuk mendapatkan seluruh objek dengan nilai maksimal ydengan meninggalkan .ydi akhir.
FistOfFury
23

Pertama, Anda harus mengurai string JSON, sehingga Anda dapat dengan mudah mengakses anggota itu:

var arr = $.parseJSON(str);

Gunakan mapmetode untuk mengekstrak nilai:

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

Kemudian Anda bisa menggunakan array dalam maxmetode:

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

Atau sebagai one-liner:

var highest = Math.max.apply(this,$.map($.parseJSON(str), function(o){ return o.y; }));
Guffa
sumber
15
Itu tidak ditandai denganjQuery
Robin van Baalen
1
@RobinvanBaalen: Ya, Anda benar. Namun tagged dengan JSON tetapi jawaban yang diterima mengabaikan itu, dan tobyodavies juga menghapus itu dari subjek pertanyaan ... Mungkin saya harus menambahkan jquery ke pertanyaan ...;)
Guffa
8
Tidak masalah banyak jika @tobyodavies mengabaikan fakta bahwa itu ditandai json- dia tidak menggunakan perpustakaan javascript eksternal dalam jawabannya :)
Robin van Baalen
23

Saya ingin menjelaskan jawaban singkat yang diterima selangkah demi selangkah:

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

Informasi lebih lanjut:

congusbongus
sumber
Penjelasan hebat! Mungkin sedikit lebih mudah untuk dibaca jika tidak ada dalam kode komentar, tetapi masih - kerja bagus
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
sumber
2
Bagaimana ini berbeda dari jawaban @ AndyPolhill?
Lewis
7

jika Anda (atau, seseorang di sini) bebas menggunakan lodashperpustakaan utilitas, ia memiliki fungsi maxBy yang akan sangat berguna dalam kasus Anda.

maka Anda dapat menggunakan seperti itu:

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

Atau semacam sederhana! Menjaga agar tetap nyata :)

array.sort((a,b)=>a.y<b.y)[0].y
Ooki Koi
sumber
Ide bagus +1 (kode terpendek), tetapi ada bug kecil - ubah a.y<a.yke b.y-a.y. Perbandingan kompleksitas waktu di sini: stackoverflow.com/a/53654364/860099
Kamil Kiełczewski
2
Menemukan max adalah O (n). Ini adalah O (nlogn). Menulis kode sederhana itu bagus asalkan efisiensi tidak dikorbankan.
Wildhammer
@Wildhammer - sebenarnya optimasi Mikro layak ketika Anda memiliki bukti bahwa Anda mengoptimalkan kemacetan. . Dalam kebanyakan kasus, kode sederhana adalah pilihan yang lebih baik daripada kode efisien tinggi.
Kamil Kiełczewski
@ KamilKiełczewski Kedua perbandingan array dalam artikel itu memiliki kompleksitas waktu yang sama perbedaannya dalam koefisien mereka. Sebagai contoh, satu membutuhkan n unit waktu untuk menemukan solusi sementara yang lain adalah 7n. Dalam teori kompleksitas waktu, keduanya adalah O (n). Apa yang kita bicarakan dalam masalah menemukan max adalah perbandingan O (n) dengan O (n logn). Sekarang jika Anda dapat menjamin n tidak melebihi 10 maka Anda dapat menggunakan solusi Anda jika O (n) algoritma selalu menjadi pemenang dan kinerja (pengalaman pengguna) selalu sebelum pengalaman pengembang (tanyakan pada orang-orang industri, mereka memberi tahu Anda!) .
Wildhammer
@Wildhammer nggak - bahkan jika array Anda memiliki n = 10.000 elemen pengguna tidak akan melihat perbedaan - bukti DI SINI . Optimalisasi kinerja hanya baik untuk hambatan aplikasi (mis. Anda perlu memproses array besar) - tetapi dalam kebanyakan kasus fokus kinerja adalah pendekatan yang salah dan membuang-buang waktu (= uang). Ini adalah kesalahan pendekatan kode yang terkenal - baca selengkapnya: "optimasi mikro"
Kamil Kiełczewski
3

Setiap array dan dapatkan nilai maksimal dengan Matematika.

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

Inilah solusi terpendek (One Liner) ES6 :

Math.max(...values.map(o => o.y));
Subodh Singh
sumber
1
var max = 0;                
jQuery.map(arr, function (obj) {
  if (obj.attr > max)
    max = obj.attr;
});
Mephisto07
sumber
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
sumber