Temukan elemen min / maks dari Array dalam JavaScript

779

Bagaimana saya bisa dengan mudah mendapatkan elemen min atau max dari JavaScript Array?

Contoh Psuedocode:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100
Terima kasih
sumber
93
Catatan: Dengan ECMAScript 6 Anda dapat menggunakan baru spread Operator (tiga titik: ...) dengan Math.max()seperti ini: Math.max(...[2, 5, 16, 1]). Lihat jawaban saya yang dibuat dari dokumentasi MDN .
totymedli
1
Pertimbangkan menandai jawaban sebagai diterima.
Alex
di sini tolok ukur untuk perbandingan kecepatan cara paling umum untuk melakukannya: jsben.ch/#/1QuTg
EscapeNetscape
es6 pada dasarnya luar biasa! :)
datdinhquoc
Tanpa ES6 Math.max.apply(null, [2,5,16,1])
Tomer

Jawaban:

828

Bagaimana dengan menambah objek Array bawaan untuk menggunakan Math.max/ Math.minsebagai gantinya:

Array.prototype.max = function() {
  return Math.max.apply(null, this);
};

Array.prototype.min = function() {
  return Math.min.apply(null, this);
};

Ini JSFiddle .

Menambah built-in dapat menyebabkan tabrakan dengan perpustakaan lain (beberapa lihat), sehingga Anda mungkin lebih nyaman dengan hanya apply'ing Math.xxx()ke array Anda secara langsung:

var min = Math.min.apply(null, arr),
    max = Math.max.apply(null, arr);

Sebagai alternatif, dengan asumsi browser Anda mendukung ECMAScript 6, Anda dapat menggunakan operator spread yang fungsinya mirip dengan applymetode ini:

var min = Math.min( ...arr ),
    max = Math.max( ...arr );
Roatin Marth
sumber
8
@HankH: lewat nullatau Mathatau {}atau apa pun apply()atau call()tidak ada hubungannya dengan hasilnya. Math.maxtidak atau tidak seharusnya merujuk secara thisinternal.
Roatin Marth
31
Sebagai seorang programmer C # saya membutuhkan pertanyaan yang sangat diketik.
ChaosPandion
7
Hanya berbagi kesalahan jQuery yang saya buat dengan kode di atas yang membutuhkan waktu lama untuk debug. Array jquery berfungsi dengan baik pada segala hal selain iPad. Saya harus mengubah array menjadi array asli yang benar agar bisa berfungsi. Hanya memengaruhi satu perangkat untuk beberapa alasanMath.max.apply(null, $.makeArray(array));
Forrest
11
Saya telah downvoted, karena pendekatan yang diusulkan mengkonsumsi O (n) memori dalam stack frame, dan sebagai hasilnya crash pada array yang besar. Dalam kasus saya, hanya sekitar 130000 angka yang cukup untuk crash nodejs.
Alexey Timanovsky
14
Jangan menambah prototip bawaan seperti ini. Ini bukan hanya tentang konflik dengan perpustakaan lain; ini juga tentang potensi yang disediakan oleh browser itu sendiri .maxatau .minmetode di masa depan. Skenario realistis yang sempurna: Anda menggunakan jawaban ini. Pada 2016, spesifikasi ES7 atau ES8 Array.maxdan Array.min. Tidak seperti versi ini, mereka bekerja pada string. Kolega Anda di masa depan mencoba untuk mendapatkan string alfabetis terbaru dalam array dengan .max()metode asli yang terdokumentasi dengan baik , tetapi secara misterius dapat NaN. Beberapa jam kemudian, dia menemukan kode ini, menjalankan git blame, dan mengutuk namamu.
Mark Amery
362
var max_of_array = Math.max.apply(Math, array);

Untuk diskusi lengkap, lihat: http://aaroncrane.co.uk/2008/11/javascript_max_api/

koran
sumber
13
Apa perbedaan antara Math.max.apply(Math, array)dan Math.max.apply(null, array)? Blog mengatakan "... Anda juga harus secara berlebihan mengatakan lagi bahwa itu maxmilik Math...", tetapi sepertinya saya tidak harus melakukannya (dengan menetapkan argumen pertama applysebagai null).
ziyuang
9
@ziyuang Ketika Anda memanggilnya seperti Math.max(a,b), Mathdilewatkan sebagai thisnilai, jadi mungkin masuk akal untuk melakukan hal yang sama saat menelepon dengan apply. Tetapi Math.maxtidak menggunakan thisnilai tersebut, sehingga Anda bisa melewati nilai apa pun yang Anda inginkan.
Oriol
199

Untuk array besar (~ 10⁷ elemen), Math.mindan Math.maxkeduanya menghasilkan kesalahan berikut di Node.js.

RangeError: Ukuran tumpukan panggilan maksimum terlampaui

Solusi yang lebih kuat adalah dengan tidak menambahkan setiap elemen ke tumpukan panggilan, tetapi untuk meneruskan array:

function arrayMin(arr) {
  return arr.reduce(function (p, v) {
    return ( p < v ? p : v );
  });
}

function arrayMax(arr) {
  return arr.reduce(function (p, v) {
    return ( p > v ? p : v );
  });
}

Jika Anda khawatir tentang kecepatan, kode berikut ~ 3 kali lebih cepat Math.max.applydari pada komputer saya. Lihat http://jsperf.com/min-and-max-in-array/2 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (arr[len] < min) {
      min = arr[len];
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (arr[len] > max) {
      max = arr[len];
    }
  }
  return max;
};

Jika array Anda mengandung string, bukan angka, Anda juga perlu memaksa mereka menjadi angka. Kode di bawah ini melakukan itu, tetapi memperlambat kode ~ 10 kali pada mesin saya. Lihat http://jsperf.com/min-and-max-in-array/3 .

function arrayMin(arr) {
  var len = arr.length, min = Infinity;
  while (len--) {
    if (Number(arr[len]) < min) {
      min = Number(arr[len]);
    }
  }
  return min;
};

function arrayMax(arr) {
  var len = arr.length, max = -Infinity;
  while (len--) {
    if (Number(arr[len]) > max) {
      max = Number(arr[len]);
    }
  }
  return max;
};
Linus Unnebäck
sumber
menetapkan mindan maxuntuk elemen terakhir dan mengurangi iterasi oleh 1 ( while(--len));)
Venugopal
@ Virugopal maka Anda perlu pemeriksaan khusus untuk melihat apakah array kosong dan kembali +/- Infinity
Linus Unnebäck
2
Aneh ... Saya pergi ke situs web yang ditautkan ... dan menguji di Firefox 51.0.0 / Mac OS X 10.12.0, pendekatan berbasis pengurangan 30% lebih lambat daripada berbasis loop ... hasil yang sangat berbeda
Pierpaolo Cira
2
very different results Anda melakukannya 5 tahun kemudian)
Алексей Лещук
1
Tahun 2019 yang reducesolusi adalah yang paling lambat. Bahkan jika Anda bekerja dengan array yang memiliki jutaan elemen, lebih baik menggunakan standar untuk loop . Lihat jawaban saya untuk lebih lanjut.
totymedli
152

Menggunakan spread operator (ES6)

Math.max(...array);  // the same with "min" => Math.min(...array);

Abdennour TOUMI
sumber
8
Solusi ini sudah disediakan oleh beberapa jawaban lain .
totymedli
15
Math.max (... []) = -Infinity. hahaha 😂😂😂
David Portabella
@ DavidVortabella tidak yakin mengapa itu lucu. Begitulah cara kerjanya sesuai dengan spesifikasi :If no arguments are given, the result is -∞.
Patrick Roberts
3
ya, saya maksudkan bahwa spesifikasi javascriptnya mengerikan. Tampak jelas bahwa angka minimum dari angka tidak dapat dihitung. Dalam bahasa pemrograman lain yang lebih serius, seperti Scala, meminta min dari array kosong melempar pengecualian.
David Portabella
3
Scala diperuntukkan bagi orang-orang yang membutuhkan mesin untuk mengatakan kepada mereka bahwa mereka salah
thedanotto
107

tl; dr

// For regular arrays:
var max = Math.max(...arrayOfNumbers);

// For arrays with tens of thousands of items:
let max = testArray[0];
for (let i = 1; i < testArrayLength; ++i) {
  if (testArray[i] > max) {
    max = testArray[i];
  }
}

Solusi MDN

Dokumen MDN resmi padaMath.max() sudah mencakup masalah ini:

Fungsi berikut menggunakan Function.prototype.apply () untuk menemukan elemen maksimum dalam array numerik. getMaxOfArray([1, 2, 3])setara dengan Math.max(1, 2, 3), tetapi Anda dapat menggunakan getMaxOfArray()pada array yang dibangun secara terprogram dari berbagai ukuran.

function getMaxOfArray(numArray) {
    return Math.max.apply(null, numArray);
}

Atau dengan operator spread baru , mendapatkan array maksimum menjadi jauh lebih mudah.

var arr = [1, 2, 3];
var max = Math.max(...arr);

Ukuran maksimum array

Menurut MDN yang applydan penyebaran solusi memiliki keterbatasan dari 65.536 yang berasal dari batas jumlah maksimum argumen:

Namun berhati-hatilah: dalam menggunakan menerapkan cara ini, Anda berisiko melampaui batas panjang argumen mesin JavaScript. Konsekuensi dari penerapan fungsi dengan terlalu banyak argumen (pikirkan lebih dari puluhan ribu argumen) bervariasi di seluruh mesin ( JavaScriptCore memiliki batas argumen hard-kode 65536 ), karena batas (memang bahkan sifat setiap tumpukan yang terlalu besar) perilaku) tidak ditentukan. Beberapa mesin akan mengeluarkan pengecualian. Lebih parah lagi, orang lain akan secara sewenang-wenang membatasi jumlah argumen yang sebenarnya diteruskan ke fungsi yang diterapkan. Untuk menggambarkan kasus terakhir ini: jika mesin seperti itu memiliki batas empat argumen (batas sebenarnya tentu saja jauh lebih tinggi), itu akan seolah-olah argumen 5, 6, 2, 3 telah dilewati untuk diterapkan dalam contoh di atas, daripada array lengkap.

Mereka bahkan menyediakan solusi hybrid yang tidak benar-benar memiliki kinerja yang baik dibandingkan dengan solusi lain. Lihat tes kinerja di bawah ini untuk informasi lebih lanjut.

Pada 2019 batas sebenarnya adalah ukuran maksimum tumpukan panggilan . Untuk browser desktop berbasis Chromium modern ini berarti bahwa ketika datang untuk mencari min / max dengan applyatau menyebar, praktis ukuran maksimum untuk angka array hanya ~ 120000 . Di atas ini, akan ada stack overflow dan kesalahan berikut akan dilemparkan:

RangeError: Ukuran tumpukan panggilan maksimum terlampaui

Dengan skrip di bawah ini (berdasarkan posting blog ini ), dengan menangkap kesalahan itu Anda dapat menghitung batas untuk lingkungan spesifik Anda.

Peringatan! Menjalankan skrip ini membutuhkan waktu dan tergantung pada kinerja sistem Anda, mungkin memperlambat atau merusak browser / sistem Anda!

let testArray = Array.from({length: 10000}, () => Math.floor(Math.random() * 2000000));
for (i = 10000; i < 1000000; ++i) {
  testArray.push(Math.floor(Math.random() * 2000000));
  try {
    Math.max.apply(null, testArray);
  } catch (e) {
    console.log(i);
    break;
  }
}

Performa pada array besar

Berdasarkan pengujian pada komentar EscapeNetscape saya membuat beberapa tolok ukur yang menguji 5 metode berbeda pada array angka acak saja dengan 100000 item .

Pada 2019, hasilnya menunjukkan bahwa loop standar (yang BTW tidak memiliki batasan ukuran) adalah yang tercepat di mana-mana. applydan penyebaran datang setelah itu, kemudian solusi hybrid MDN kemudian reducesebagai yang paling lambat.

Hampir semua tes memberikan hasil yang sama, kecuali untuk tes yang penyebarannya paling lambat.

Jika Anda meningkatkan array Anda untuk memiliki 1 juta item, hal-hal mulai rusak dan Anda dibiarkan dengan loop standar sebagai solusi cepat dan reducelebih lambat.

Tolok ukur JSPerf

jsperf.com hasil benchmark untuk berbagai solusi untuk menemukan item minimum / maksimum dari sebuah array

Tolok ukur JSBen

jsben.com hasil benchmark untuk berbagai solusi untuk menemukan item minimum / maksimum dari sebuah array

Tolok ukur JSBench.me

jsbench.me hasil benchmark untuk berbagai solusi untuk menemukan item min / max dari sebuah array

Kode sumber patokan

totymedli
sumber
Jika Anda menggunakan naskah, operator spread seperti yang ditunjukkan dikompilasi Math.max.apply(Math, arr)untuk kompatibilitas 'maks'.
Simon_Weaver
1
Juga dari MDN: "keduanya menyebar (...)dan applyakan gagal atau mengembalikan hasil yang salah jika array memiliki terlalu banyak elemen [...] Solusi pengurangan tidak memiliki masalah ini" Pengujian Chrome, FF, Edge dan IE11 tampaknya seperti itu adalah ok untuk array hingga nilai 100k. (Diuji pada Win10 dan browser terbaru: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam
Ini adalah metode yang sangat lambat, bagaimana jika array akan memiliki ribuan elemen?
Slava Fomin II
@SlavaFominII Saya memberikan jawabannya sehingga mencakup array dengan ribuan elemen.
totymedli
68

Jika Anda paranoid seperti saya tentang penggunaan Math.max.apply(yang dapat menyebabkan kesalahan saat diberi array besar sesuai dengan MDN ), coba ini:

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.max(a, b);
  });
}

function arrayMin(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  });
}

Atau, dalam ES6:

function arrayMax(array) {
  return array.reduce((a, b) => Math.max(a, b));
}

function arrayMin(array) {
  return array.reduce((a, b) => Math.min(a, b));
}

Sayangnya, fungsi anonim diperlukan (alih-alih menggunakan Math.max.bind(Math)karena reducetidak hanya meneruskan adan bke fungsinya, tetapi juga idan referensi ke array itu sendiri, jadi kami harus memastikan kami tidak mencoba memanggilnya maxjuga.

Daniel Buckmaster
sumber
Contoh ES6 Anda, apakah ada alasan mengapa tidak kembali saja Math.max(...array)?
Wojciech Bednarski
@WojciechBednarski halaman ini tampaknya menyarankan bahwa menggunakan operator spread sama dengan melewatkan array apply, dan oleh karena itu memiliki kelemahan yang sama (batas argumen maksimum).
Daniel Buckmaster
Terima kasih untuk ini. Hanya Anda dapat memperbaiki braket yang hilang setelah mengurangi:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky
1
@DanielDietrich Saya kira melakukan hal yang sama, memanggil Math.min()tanpa nilai, kembali Infinity, jadi fungsi ini bisa digunakan reduce(..., Infinity)untuk mencocokkan perilaku itu. Saya lebih suka untuk melempar pengecualian (seperti halnya saat ini), karena mengambil minimum array kosong sepertinya merupakan kesalahan.
Daniel Buckmaster
1
sejauh ini pengurangan adalah yang paling lambat.
Алексей Лещук
40

.apply sering digunakan ketika tujuannya adalah untuk memanggil fungsi variad dengan daftar nilai argumen, misalnya

The Math.max([value1[,value2, ...]])fungsi mengembalikan terbesar dari nol atau lebih nomor.

Math.max(10, 20); // 20
Math.max(-10, -20); // -10
Math.max(-10, 20); // 20

The Math.max()Metode tidak memungkinkan Anda untuk lulus dalam array. Jika Anda memiliki daftar nilai yang Anda butuhkan untuk mendapatkan yang terbesar, Anda biasanya akan memanggil fungsi ini menggunakan Function.prototype.apply () , misalnya

Math.max.apply(null, [10, 20]); // 20
Math.max.apply(null, [-10, -20]); // -10
Math.max.apply(null, [-10, 20]); // 20

Namun, pada ECMAScript 6 Anda dapat menggunakan operator spread :

Operator spread memungkinkan ekspresi diperluas di tempat-tempat di mana banyak argumen (untuk panggilan fungsi) atau beberapa elemen (untuk liter array) diharapkan.

Menggunakan operator spread, yang di atas dapat ditulis ulang seperti:

Math.max(...[10, 20]); // 20
Math.max(...[-10, -20]); // -10
Math.max(...[-10, 20]); // 20

Saat memanggil fungsi menggunakan operator variadic, Anda bahkan dapat menambahkan nilai tambahan, mis

Math.max(...[10, 20], 50); // 50
Math.max(...[-10, -20], 50); // 50

Bonus:

Operator spread memungkinkan Anda untuk menggunakan array literal sintaks untuk membuat array baru dalam situasi di mana di ES5 Anda akan perlu untuk jatuh kembali ke kode penting, menggunakan kombinasi push, splicedll

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']
Gajus
sumber
1
Contoh terakhir Anda dalam bonus akan ditulis menggunakan concatsebagian besar programmer karena memungkinkan Anda mempertahankan gaya baris tunggal.
Cody Allan Taylor
31

Dua cara lebih pendek dan mudah:

let arr = [2, 6, 1, 0]

Cara 1 :

let max = Math.max.apply(null, arr)

Cara 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});
Hafizur Rahman
sumber
Hati-hati jika array kosong - Anda akan mendapatkan infinity negatif yang mungkin bukan yang Anda inginkan. Jika Anda memilih untuk 0menggunakannya, Anda dapat menggunakan [0].concat(arr)atau dengan sintaks spread [0, ...arr](sebagai ganti 'arr')
Simon_Weaver
apakah ada cara untuk mengecualikan nilai nol di Cara 1?
bonbon.langes
22

Anda melakukannya dengan memperluas tipe Array:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};
Array.min = function( array ){
    return Math.min.apply( Math, array );
}; 

Didorong dari sini (oleh John Resig)

inkedmn
sumber
20

Solusi sederhana untuk menemukan nilai minimum atas Arrayelemen adalah dengan menggunakan Arrayfungsi prototipe reduce:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min ? val : min, A[0]); // returns -9

atau menggunakan fungsi Math.Min () bawaan JavaScript (terima kasih @Tenflex):

A.reduce((min,val) => Math.min(min,val), A[0]);

Ini diatur minke A[0], dan kemudian memeriksa A[1]...A[n]apakah itu benar-benar kurang dari saat ini min. Jika A[i] < minkemudian mindiperbarui ke A[i]. Ketika semua elemen array telah diproses, mindikembalikan sebagai hasilnya.

EDIT : Sertakan posisi nilai minimum:

A = [4,3,-9,-2,2,1];
A.reduce((min, val) => val < min._min ? {_min: val, _idx: min._curr, _curr: min._curr + 1} : {_min: min._min, _idx: min._idx, _curr: min._curr + 1}, {_min: A[0], _idx: 0, _curr: 0}); // returns { _min: -9, _idx: 2, _curr: 6 }
Nicolas Lykke Iversen
sumber
3
A.reduce ((min, val) => Math.min (min, val), A [0]); bahkan lebih pendek
Tenflex
Sebagai pertanyaan bonus, bagaimana agar minnilai tidak hanya dikembalikan tetapi juga posisinya di Array?
stevek
@meshfields - Saya sudah memperbarui jawabannya.
Nicolas Lykke Iversen
15

Yang lain telah memberikan beberapa solusi yang mereka tambahkan Array.prototype. Yang saya inginkan dalam jawaban ini adalah untuk menjelaskan apakah seharusnya Math.min.apply( Math, array )atau tidak Math.min.apply( null, array ). Jadi konteks apa yang harus digunakan, Mathatau null?

Ketika lewat nullsebagai konteks apply, maka konteksnya akan default ke objek global ( windowobjek dalam hal browser). Melewati Mathobjek sebagai konteks akan menjadi solusi yang tepat, tetapi tidak ada salahnya lewat nulljuga. Berikut ini contoh saat nulldapat menyebabkan masalah, saat mendekorasi Math.maxfungsi:

// decorate Math.max
(function (oldMax) {
    Math.max = function () {
        this.foo(); // call Math.foo, or at least that's what we want

        return oldMax.apply(this, arguments);
    };
})(Math.max);

Math.foo = function () {
    print("foo");
};

Array.prototype.max = function() {
  return Math.max.apply(null, this); // <-- passing null as the context
};

var max = [1, 2, 3].max();

print(max);

Di atas akan membuang pengecualian karena this.fooakan dievaluasi sebagai window.foo, yaitu undefined. Jika kita ganti nulldengan Math, semuanya akan berfungsi seperti yang diharapkan dan string "foo" akan dicetak ke layar (saya menguji ini menggunakan Mozilla Rhino ).

Anda dapat dengan mudah berasumsi bahwa tidak ada seorang pun yang didekorasi Math.maxdemikian, passing nullakan bekerja tanpa masalah.

Ionuț G. Stan
sumber
2
Poin yang diambil. Namun mengapa seseorang menghias Foo.staticMethoddan referensi this? Apakah itu tidak akan menjadi kesalahan dalam desain dekorator? (kecuali tentu saja mereka ingin referensi lingkup global, dan ingin tetap independen dari mesin JavaScript yang digunakan, misalnya Badak).
Roatin Marth
1
Spesifikasinya eksplisit tentang fungsi spesifik mana yang harus merujuk pada "nilai ini " (memang, frasa itu muncul 125 kali dalam spesifikasi). Math.max, diterapkan per spec, tidak digunakan this. Jika seseorang menimpa Math.maxsedemikian rupa sehingga tidak digunakan this, maka mereka telah membuat perilakunya melanggar spec dan Anda harus melemparkan benda tajam pada mereka. Anda tidak boleh kode di sekitar kemungkinan itu lebih dari yang Anda kode di sekitar kemungkinan bahwa seseorang telah bertukar Math.maxdan Math.minuntuk lulz.
Mark Amery
15

Satu lagi cara untuk melakukannya:

var arrayMax = Function.prototype.apply.bind(Math.max, null);

Pemakaian:

var max = arrayMax([2, 5, 1]);
sbr
sumber
Adakah yang bisa menjelaskan cara kerjanya? Ini sangat bodoh. Apakah pemahaman saya benar: arrayMax adalah fungsi dan kami mengikat sesuatu ke properti prototipe-nya? Apa ini berlaku.bind dan apakah setiap prototipe memilikinya?
Sam
14

Metode Alternatif


Metode Math.mindan Math.maxkeduanya adalah operasi rekursif yang ditambahkan ke tumpukan panggilan mesin JS, dan kemungkinan besar crash untuk array yang berisi sejumlah besar item
(lebih dari ~ 10⁷ item, tergantung pada browser pengguna).

Math.max (... Array (1000000) .key ());

Uncaught RangeError: Ukuran stack panggilan maksimum terlampaui

Sebagai gantinya, gunakan sesuatu seperti:

arr.reduce((max, val) => max > val ? max : val, arr[0])

Atau dengan run-time yang lebih baik:

function maxValue(arr) {
  let max = arr[0];

  for (let val of arr) {
    if (val > max) {
      max = val;
    }
  }
  return max;
}

Atau untuk mendapatkan Min dan Max:

function getMinMax(arr) {
  return arr.reduce(({min, max}, v) => ({
    min: min < v ? min : v,
    max: max > v ? max : v,
  }), { min: arr[0], max: arr[0] });
}

Atau dengan run-time * yang lebih baik:

function getMinMax(arr) {
  let min = arr[0];
  let max = arr[0];
  let i = arr.length;

  while (i--) {
    min = arr[i] < min ? arr[i] : min;
    max = arr[i] > max ? arr[i] : max;
  }
  return { min, max };
}

* Diuji dengan 1.000.000 item:
Hanya untuk referensi, fungsi run-time 1 (pada mesin saya) adalah 15,84 ms vs fungsi 2 dengan hanya 4,32 ms.

Lior Elrom
sumber
13

Ini mungkin sesuai dengan tujuan Anda.

Array.prototype.min = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.min);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}

Array.prototype.max = function(comparer) {

    if (this.length === 0) return null;
    if (this.length === 1) return this[0];

    comparer = (comparer || Math.max);

    var v = this[0];
    for (var i = 1; i < this.length; i++) {
        v = comparer(this[i], v);    
    }

    return v;
}
Kekacauan Kekacauan
sumber
Anda harus menginisialisasi v Anda dengan 'ini [0]' dalam kasus tidak ada angka yang lebih kecil dari 0
jasonmw
Apakah comparerseharusnya dipanggil dalam lingkup tertentu? Karena sebagaimana adanya referensi this[index]yang undefinedsetiap saat.
Roatin Marth
Tetap, saya selalu lupa tentang pelingkupan tingkat fungsi.
ChaosPandion
Oh sekarang, sekarang @Ionut G. Stan akan mengkritik Anda untuk argumen "konteks yang salah" yang sama dengan yang saya lakukan, karena pembanding default Anda ( Math.xxx) akan berjalan dalam lingkup global ...
Roatin Marth
Itu mungkin benar, tetapi tanda tangan fungsi baru tidak memerlukan ruang lingkup karena dibutuhkan 2 objek yang perlu dibandingkan.
ChaosPandion
12

Saya kaget tidak salah menyebut dan mengurangi fungsinya.

var arr = [1, 10, 5, 11, 2]

var b = arr.reduce(function(previous,current){ 
                      return previous > current ? previous:current
                   });

b => 11
arr => [1, 10, 5, 11, 2]
Stallion_V
sumber
Waspada: kurangi () didukung dari IE9, lihat developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Paul Gobée
1
Sepertinya saya tidak dapat menggunakan ini di versi Chromium saat ini.
PJSCopeland
9

Untuk array besar (~ 10⁷ elemen), Math.mindan Math.maxmenghasilkan RangeError (ukuran stack panggilan maksimum terlampaui) di node.js.

Untuk array besar, solusi cepat & kotor adalah:

Array.prototype.min = function() {
    var r = this[0];
    this.forEach(function(v,i,a){if (v<r) r=v;});
    return r;
};
Peter
sumber
8

Saya memiliki masalah yang sama, saya perlu mendapatkan nilai minimum dan maksimum dari sebuah array dan, yang mengejutkan saya, tidak ada fungsi built-in untuk array. Setelah banyak membaca, saya memutuskan untuk menguji sendiri solusi "3 teratas":

  1. solusi diskrit: loop UNTUK untuk memeriksa setiap elemen array terhadap nilai maks dan / atau min saat ini;
  2. BERLAKU solusi: mengirim array ke fungsi internal Math.max dan / atau Math.min menggunakan apply (null, array);
  3. Solusi REDUCE: berulang cek terhadap setiap elemen array menggunakan mengurangi (fungsi).

Kode tes adalah ini:

function GetMaxDISCRETE(A)
{   var MaxX=A[0];

    for (var X=0;X<A.length;X++)
        if (MaxX<A[X])
            MaxX=A[X];

    return MaxX;
}

function GetMaxAPPLY(A)
{   return Math.max.apply(null,A);
}

function GetMaxREDUCE(A)
{   return A.reduce(function(p,c)
    {   return p>c?p:c;
    });
}

Array A diisi dengan 100.000 angka integer acak, setiap fungsi dijalankan 10.000 kali pada Mozilla Firefox 28.0 pada desktop intel Pentium 4 2.99GHz dengan Windows Vista. Waktu dalam detik, diambil oleh fungsi performance.now (). Hasilnya adalah ini, dengan 3 digit fraksional dan deviasi standar:

  1. Solusi diskrit: rata-rata = 0,161d, sd = 0,078
  2. BERLAKU solusi: berarti = 3.571, sd = 0.487
  3. Solusi REDUCE: mean = 0,350s, sd = 0,044

Solusi REDUCE lebih lambat 117% dari solusi diskrit. Solusi BERLAKU lebih buruk, 2.118% lebih lambat dari solusi diskrit. Selain itu, seperti yang diamati Peter, itu tidak berfungsi untuk array besar (sekitar lebih dari 1.000.000 elemen).

Juga, untuk menyelesaikan tes, saya menguji kode terpisah yang diperluas ini:

var MaxX=A[0],MinX=A[0];

for (var X=0;X<A.length;X++)
{   if (MaxX<A[X])
        MaxX=A[X];
    if (MinX>A[X])
        MinX=A[X];
}

Waktunya: mean = 0,218s, sd = 0,094

Jadi, 35% lebih lambat dari solusi diskrit sederhana, tetapi ia mengambil nilai maksimum dan minimum sekaligus (solusi lain akan membutuhkan setidaknya dua kali lipat untuk mengambilnya). Setelah OP membutuhkan kedua nilai tersebut, solusi diskrit akan menjadi pilihan terbaik (meskipun dua fungsi terpisah, satu untuk menghitung maksimum dan satu lagi untuk menghitung minimum, mereka akan mengungguli yang terbaik kedua, solusi REDUCE).

Cyberknight
sumber
8

Anda dapat menggunakan fungsi berikut di mana saja di proyek Anda:

function getMin(array){
    return Math.min.apply(Math,array);
}

function getMax(array){
    return Math.max.apply(Math,array);
}

Dan kemudian Anda bisa memanggil fungsi yang melewati array:

var myArray = [1,2,3,4,5,6,7];
var maximo = getMax(myArray); //return the highest number
Max Cabrera
sumber
8

Kode berikut ini berfungsi untuk saya:

var valueList = [10,4,17,9,3];
var maxValue = valueList.reduce(function(a, b) { return Math.max(a, b); });
var minValue = valueList.reduce(function(a, b) { return Math.min(a, b); });
jaydip jadhav
sumber
7

Iterasi melalui, melacak saat Anda pergi.

var min = null;
var max = null;
for (var i = 0, len = arr.length; i < len; ++i)
{
    var elem = arr[i];
    if (min === null || min > elem) min = elem;
    if (max === null || max < elem) max = elem;
}
alert( "min = " + min + ", max = " + max );

Ini akan meninggalkan min / max null jika tidak ada elemen dalam array. Akan menetapkan min dan maks dalam satu lintasan jika array memiliki elemen apa pun.

Anda juga dapat memperluas Array dengan rangemetode menggunakan di atas untuk memungkinkan penggunaan kembali dan meningkatkan keterbacaan. Lihat biola yang berfungsi di http://jsfiddle.net/9C9fU/

Array.prototype.range = function() {

    var min = null,
        max = null,
        i, len;

    for (i = 0, len = this.length; i < len; ++i)
    {
        var elem = this[i];
        if (min === null || min > elem) min = elem;
        if (max === null || max < elem) max = elem;
    }

    return { min: min, max: max }
};

Digunakan sebagai

var arr = [3, 9, 22, -7, 44, 18, 7, 9, 15];

var range = arr.range();

console.log(range.min);
console.log(range.max);
tvanfosson
sumber
@JordanDillonChapian saya setuju, tetapi akan sepele untuk memperluas ini ke rangefungsi yang akan menjadi cara terbaik untuk mendapatkan min dan max pada saat yang sama IMO - seperti yang telah saya lakukan dengan pembaruan untuk jawaban saya.
tvanfosson
6

Saya pikir saya akan membagikan solusi saya yang sederhana dan mudah dipahami.

Untuk min:

var arr = [3, 4, 12, 1, 0, 5];
var min = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] < min) {
    min = arr[k];
  }
}
console.log("Min is: " + min);

Dan untuk maks:

var arr = [3, 4, 12, 1, 0, 5];
var max = arr[0];
for (var k = 1; k < arr.length; k++) {
  if (arr[k] > max) {
    max = arr[k];
  }
}
console.log("Max is: " + max);

Ionut Necula
sumber
Terima kasih. Saya mengubah jawaban saya.
Ionut Necula
Iterasi masih salah (mengakses properti yang tidak ada).
Bergi
Apa yang salah, saya tidak melihat sesuatu yang salah. Bisakah Anda memberikan contoh?
Ionut Necula
1
Dimodifikasi sesuai sekarang. Semoga saya mengerti Anda dengan benar.
Ionut Necula
5

Hal-hal sederhana, sungguh.

var arr = [10,20,30,40];
arr.max = function() { return  Math.max.apply(Math, this); }; //attach max funct
arr.min = function() { return  Math.min.apply(Math, this); }; //attach min funct

alert("min: " + arr.min() + " max: " + arr.max());
Brian
sumber
5

Inilah salah satu cara untuk mendapatkan nilai maksimal dari berbagai objek. Buat salinan (dengan irisan), lalu urutkan salinan dalam urutan menurun dan ambil item pertama.

var myArray = [
    {"ID": 1, "Cost": 200},
    {"ID": 2, "Cost": 1000},
    {"ID": 3, "Cost": 50},
    {"ID": 4, "Cost": 500}
]

maxsort = myArray.slice(0).sort(function(a, b) { return b.ID - a.ID })[0].ID; 
Ben
sumber
5

Menggunakan Math.max()atauMath.min()

Math.max(10, 20);   //  20
Math.min(-10, -20); // -20

Fungsi berikut digunakan Function.prototype.apply()untuk menemukan elemen maksimum dalam array numerik. getMaxOfArray([1, 2, 3])setara dengan Math.max(1, 2, 3), tetapi Anda dapat menggunakan getMaxOfArray()pada array yang dibangun secara terprogram dari berbagai ukuran.

function getMaxOfArray(numArray) {
  return Math.max.apply(null, numArray);
}

Atau dengan operator spread baru, mendapatkan array maksimum menjadi jauh lebih mudah.

var arr = [1, 2, 3];
var max = Math.max(...arr); // 3
var min = Math.min(...arr); // 1
shilovk
sumber
5

Selain menggunakan fungsi matematika maks dan min, fungsi lain yang digunakan adalah fungsi bawaan sortir (): ayo kita mulai

const nums = [12, 67, 58, 30].sort((x, y) => 
x -  y)
let max = nums[0]
let min = nums[nums.length -1]
Pedro JR
sumber
4

Solusi ChaosPandion berfungsi jika Anda menggunakan protoype. Jika tidak, pertimbangkan ini:

Array.max = function( array ){
    return Math.max.apply( Math, array );
};

Array.min = function( array ){
    return Math.min.apply( Math, array );
};

Di atas akan mengembalikan NaN jika nilai array bukan bilangan bulat sehingga Anda harus membangun beberapa fungsi untuk menghindarinya. Kalau tidak, ini akan berhasil.

jay
sumber
jeerose, mengapa Anda memiliki (Matematika, ini) sebagai warisan ketika Roatin Marth hanya memiliki (null, ini)?
HankH
@HankH: lihat tanggapan saya terhadap komentar Anda dalam komentar atas jawaban saya sendiri.
Roatin Marth
1
Saya tidak mengerti apa yang Anda maksud dengan "solusi ChaosPandion bekerja jika Anda menggunakan protoype". Bagaimana solusi Anda berbeda, kecuali Anda menggunakan Mathobjek sebagai konteksnya?
Ionuț G. Stan
Maaf, maksud saya jika Anda memperpanjang prototipe milik Anda akan bekerja. Permintaan maaf.
jay
Jadi mana yang lebih baik, jeerose atau ChaosPandion?
HankH
3

Jika Anda menggunakan library sugar.js , Anda dapat menulis arr.min () dan arr.max () seperti yang Anda sarankan. Anda juga bisa mendapatkan nilai min dan maks dari array non-numerik.

min (peta, semua = false) Mengembalikan elemen dalam array dengan nilai terendah. map bisa berupa fungsi yang memetakan nilai yang akan diperiksa atau string yang bertindak sebagai jalan pintas. Jika semuanya benar, akan mengembalikan semua nilai min dalam array.

maks (peta, semua = false) Mengembalikan elemen dalam array dengan nilai terbesar. map bisa berupa fungsi yang memetakan nilai yang akan diperiksa atau string yang bertindak sebagai jalan pintas. Jika semuanya benar, akan mengembalikan semua nilai maks dalam array.

Contoh:

[1,2,3].min() == 1
['fee','fo','fum'].min('length') == "fo"
['fee','fo','fum'].min('length', true) == ["fo"]
['fee','fo','fum'].min(function(n) { return n.length; }); == "fo"
[{a:3,a:2}].min(function(n) { return n['a']; }) == {"a":2}
['fee','fo','fum'].max('length', true) == ["fee","fum"]

Perpustakaan seperti Lo-Dash dan underscore.js juga menyediakan fungsi min dan maks yang kuat serupa:

Contoh dari Lo-Dash:

_.max([4, 2, 8, 6]) == 8
var characters = [
  { 'name': 'barney', 'age': 36 },
  { 'name': 'fred',   'age': 40 }
];
_.max(characters, function(chr) { return chr.age; }) == { 'name': 'fred', 'age': 40 }
andersh
sumber
3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1
UA_
sumber
2
Solusi ini telah disediakan oleh beberapa penjawab lain untuk pertanyaan ini. Apa yang ditambahkan jawaban Anda?
Nick
3

Mencoba

let max= a=> a.reduce((m,x)=> m>x ? m:x);
let min= a=> a.reduce((m,x)=> m<x ? m:x);

Untuk Math.min / maks (+ terapkan) kami mendapatkan kesalahan:

Ukuran tumpukan panggilan maksimum terlampaui (Chrome 74.0.3729.131)

Kamil Kiełczewski
sumber