JavaScript'te bir Dizinin min / maks öğesini bulun


779

Bir JavaScript Dizisinin min veya maks öğesini nasıl kolayca edinebilirim?

Örnek Psuedocode:

let array = [100, 0, 50]

array.min() //=> 0
array.max() //=> 100

93
Not: Yeni kullanabilirsiniz ECMAScript 6 ile yayıldı operatörünü : (üç nokta ...ile) Math.max()böyle: Math.max(...[2, 5, 16, 1]). MDN dokümanlarından verilen cevabımı görün .
totymedli

1
Bir cevabı kabul edilmiş olarak işaretlemeyi düşünün.
Alex

İşte bunu yapmanın en yaygın yollarının hız karşılaştırması için bir kıyaslama: jsben.ch/#/1QuTg
EscapeNetscape

es6 temelde mükemmel! :)
datdinhquoc

ES6'sız Math.max.apply(null, [2,5,16,1])
Tomer

Yanıtlar:


828

Nasıl artırmada yaklaşık yerleşik kullanmak Dizi nesne Math.max/ Math.minyerine:

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

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

İşte bir JSFiddle .

Yerleşikleri genişletmek, diğer kütüphanelerle çarpışmalara neden olabilir (bazıları bkz.), Bu nedenle doğrudan dizinize applygitme konusunda daha rahat olabilirsiniz Math.xxx():

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

Alternatif olarak, tarayıcınızın ECMAScript 6'yı desteklediğini varsayarsak , yönteme benzer şekilde çalışan forma operatörünü kullanabilirsiniz apply:

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

8
@HankH: geçen nullya Mathya {}ya neyse apply()ya call()sonuç ile bir ilgisi yoktur. dahili Math.maxreferans vermez veya göndermemelidir this.
Roatin Marth

31
Bir C # programcısı olarak ben güçlü yazılan sorular gerektirir.
ChaosPandion

7
Sadece hata ayıklamak için uzun zaman aldı yukarıdaki kod ile yapıyordum bir jQuery hata paylaşımı. Bir jquery dizisi iPad dışında her şeyde iyi çalışır. Çalışması için diziyi gerçek bir yerel diziye dönüştürmek zorunda kaldım. Tek bir cihazı sadece bir nedenden dolayı etkilediMath.max.apply(null, $.makeArray(array));
Forrest

11
Önerilen yaklaşım yığın çerçevesindeki O (n) belleği tüketir ve sonuç olarak büyük dizilerde çöker. Benim durumumda sadece 130000 sayı nodejsleri çökertmek için yeterliydi.
Alexey Timanovsky

14
Bunun gibi yerleşik prototipleri büyütmeyin. Bu sadece diğer kütüphanelerle olan çatışmalarla ilgili değil; ayrıca tarayıcının kendisinin gelecekte bir .maxveya .minyöntem sağlaması potansiyeli ile ilgilidir . Mükemmel gerçekçi senaryo: Bu cevabı kullanıyorsunuz. 2016 yılında, ES7 veya ES8 spec Array.maxve Array.min. Bu sürümden farklı olarak, dizeler üzerinde çalışırlar. Gelecekteki iş arkadaşınız, şimdi iyi belgelenmiş yerel .max()yöntemle bir dizide alfabetik olarak en son dizeyi almaya çalışır , ancak gizemli bir şekilde alır NaN. Saatler sonra bu kodu bulur, a çalıştırır git blameve adınızı lanetler.
Mark Amery

362
var max_of_array = Math.max.apply(Math, array);

Tam bir tartışma için bkz. Http://aaroncrane.co.uk/2008/11/javascript_max_api/


13
Arasındaki fark nedir Math.max.apply(Math, array)ve Math.max.apply(null, array)? Blog, "... aynı zamanda tekrar buna maxait olduğunu da söylemelisin Math..." diyor, ama öyle görünmüyor (ilk applyas argümanını ayarlayarak null).
ziyuang

9
Eğer gibi aradığınızda @ziyuang Math.max(a,b), Matholarak geçirilir thisonunla çağrılırken aynı şeyi mantıklı olabilir, böylece değer apply. Ancak değeri Math.maxkullanmaz this, böylece istediğiniz değeri iletebilirsiniz.
Oriol

199

Büyük diziler için (~ 10⁷ elemanlar) Math.minve Math.maxher ikisi de Node.js'de aşağıdaki hatayı üretir.

RangeError: Maksimum çağrı yığını boyutu aşıldı

Daha sağlam bir çözüm, her öğeyi çağrı yığınına eklemek değil, bunun yerine bir dizi iletmektir:

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

Hız konusunda endişeleriniz varsa, aşağıdaki kod Math.max.applybilgisayarımda ~ 3 kat daha hızlıdır . Bkz. 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;
};

Dizileriniz sayılar yerine dizeler içeriyorsa, sayılara da zorlamanız gerekir. Aşağıdaki kod bunu yapar, ancak makinemde kodu ~ 10 kez yavaşlatır. Bkz. 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;
};

atamak minve maxson eleman ve iterasyonları azaltmak 1 ( while(--len));)
Venugopal

@Venugopal o zaman dizi boş olup olmadığını görmek için özel bir kontrol gerekir ve +/- Infinity
Linus Unnebäck

2
Garip ... Bağlantılı web sitesine gittim ... ve Firefox 51.0.0 / Mac OS X 10.12.0'da test ettim, azaltmaya dayalı yaklaşım döngü tabanlı olandan% 30 daha yavaş ... çok farklı sonuçlar
Pierpaolo Cira

2
very different results bunu 5 yıl sonra yaptınız)
Алексей Лещук

1
2019 yılındareduce çözelti yavaş olanıdır. Milyonlarca öğe içeren bir dizi ile çalışsanız bile, döngü için standart kullanmak daha iyidir . Daha fazla bilgi için cevabımı görün.
totymedli

152

Forma operatörünü (ES6) kullanma

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


8
Bu çözüm zaten başka birçok cevapla sağlandı .
totymedli

15
Math.max (... []) = -Binlik. hahaha
David

@DavidPortabella bunun neden komik olduğundan emin değil. Şartnameye göre şu şekilde çalışır :If no arguments are given, the result is -∞.
Patrick Roberts

3
evet, javascript spesifikasyonunun korkunç olduğunu kastediyorum. Hiçbir sayının min değerinin hesaplanamadığı açıktır. Scala gibi diğer daha ciddi programlama dillerinde ise, boş bir dizinin dakikasını istemek bir istisna atar.
David Portabella

3
Scala, yanlış yaptıklarını söylemek için bir makineye ihtiyaç duyan insanlar için
thedanotto

106

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

MDN çözümü

Üzerindeki resmi MDN belgeleriMath.max() zaten bu sorunu kapsamaktadır:

Aşağıdaki işlev, sayısal bir dizideki maksimum öğeyi bulmak için Function.prototype.apply () öğesini kullanır . getMaxOfArray([1, 2, 3])eşdeğerdir Math.max(1, 2, 3), ancak getMaxOfArray()herhangi bir boyuttaki programlı olarak oluşturulmuş dizilerde kullanabilirsiniz .

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

Ya da yeni forma operatörü ile bir dizinin maksimumu elde etmek çok daha kolay hale gelir.

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

Bir dizinin maksimum boyutu

MDN'yi göreapply ve yayılma çözümleri vardı argümanlar maksimum sayıda sınırının geldi 65536 bir sınırlama:

Ancak dikkat: Uygulamayı bu şekilde kullanırken, JavaScript motorunun bağımsız değişken uzunluk sınırını aşma riskiniz vardır. Çok fazla bağımsız değişkeni olan bir işlevi uygulamanın sonuçları (on binlerce argümandan fazla düşünün) motorlar arasında farklılık gösterir ( JavaScriptCore'un sabit kodlu argüman sınırı 65536'dır ), çünkü sınır (hatta aşırı büyük yığınların doğası bile) davranış) belirtilmemiş. Bazı motorlar bir istisna atar. Daha korkutucu bir şekilde, diğerleri keyfi olarak uygulanan işleve iletilen argüman sayısını sınırlandıracaktır. Bu son durumu göstermek için: eğer böyle bir motor dört argüman sınırına sahip olsaydı (gerçek sınırlar elbette önemli ölçüde daha yüksekse), yukarıdaki örneklerde uygulanacak 5, 6, 2, 3 argümanlarının geçirilmiş olması gibi olurdu, tam dizi yerine.

Hatta diğer çözümlere kıyasla gerçekten iyi bir performansa sahip olmayan hibrit bir çözüm sunarlar. Daha fazla bilgi için aşağıdaki performans testine bakın.

2019'da gerçek sınır, çağrı yığınının maksimum boyutudur . Modern Chromium tabanlı masaüstü tarayıcıları için bu, min / maks ile applyveya yayılarak bulma söz konusu olduğunda , pratik olarak yalnızca diziler için maksimum boyutun ~ 120000 olduğu anlamına gelir . Bunun üzerinde bir yığın taşması olacak ve aşağıdaki hata atılacaktır:

RangeError: Maksimum çağrı yığını boyutu aşıldı

Aşağıdaki komut dosyasıyla ( bu blog gönderisini temel alarak ), bu hatayı yakalayarak, ortamınıza özgü sınırı hesaplayabilirsiniz.

Uyarı! Bu komut dosyasını çalıştırmak zaman alır ve sisteminizin performansına bağlı olarak tarayıcınızı / sisteminizi yavaşlatabilir veya bozabilir!

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

Büyük dizilerde performans

EscapeNetscape'in yorumundaki teste dayanarak, rastgele bir sayı dizisinde sadece 100000 öğe içeren 5 farklı yöntemi test eden bazı ölçütler oluşturdum .

2019'da sonuçlar, standart döngünün (BTW'nin boyut sınırlamasına sahip olmadığı) her yerde en hızlı olduğunu gösteriyor. applyve yayılma ondan sonra yakından gelir, daha sonra MDN'nin hibrit çözümü o zaman reduceen yavaş olanıdır.

Hemen hemen tüm testler aynı sonuçları verdi, ancak bir şekilde yayılmanın en yavaş olduğu bir durum hariç.

Dizinizi 1 milyon öğeye sahip olacak şekilde hızlandırırsanız, işler kırılmaya başlar ve standart döngüde hızlı bir çözüm ve reducedaha yavaş olarak kalırsınız .

JSPerf karşılaştırması

Bir dizinin min / maks öğesini bulmak için farklı çözümler için jsperf.com karşılaştırma sonuçları

JSBen karşılaştırması

Bir dizinin min / maks öğesini bulmak için farklı çözümler için jsben.com karşılaştırma sonuçları

JSBench.me karşılaştırması

Bir dizinin min / maks öğesini bulmak için farklı çözümler için jsbench.me karşılaştırma sonuçları

Karşılaştırma kaynak kodu


Typescript kullanıyorsanız, gösterildiği gibi forma operatörü Math.max.apply(Math, arr)'max' uyumluluğu için derlenir .
Simon_Weaver

1
Ayrıca MDN: " dizi yayılır (...)ve applydizi çok fazla öğe varsa ya başarısız olur veya yanlış sonuç döndürür [...] Azaltma çözümü bu sorunu yok" Chrome, FF, Edge ve IE11 test gibi görünüyor 100k değerine kadar bir dizi için ok. (Win10 ve en son tarayıcılarda test edilmiştir: Chrome 110k, Firefox 300k, Edge 400k, IE11 150k).
oriadam

Bu çok yavaş bir yöntemdir, dizi binlerce öğeye sahip olsaydı?
Slava Fomin II

@SlavaFominII Cevabı binlerce eleman içeren dizileri kapsayacak şekilde genişlettim.
totymedli

68

Benim gibi paranoyaksanız Math.max.apply( MDN'ye göre büyük diziler verildiğinde hatalara neden olabilir ), şunu deneyin:

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

Veya ES6'da:

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

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

Anonim işlevler maalesef gerekli (kullanmak yerine vardır Math.max.bind(Math)çünkü reducesadece geçmez ave bonun işlevine değil, aynı zamanda ibiz aramaya kalkma sağlamak zorunda ve dizinin kendisi bir referans maxsıra olanlara.


ES6 örneğiniz, sadece geri dönmemenizin bir nedeni var Math.max(...array)mı?
Wojciech Bednarski

@WojciechBednarski bu sayfa forma operatörünü kullanmanın bir diziye geçişle aynı olduğunu applyve bu nedenle aynı dezavantajları olduğunu (maksimum bağımsız değişken sınırı) öne sürüyor gibi görünüyor .
Daniel Buckmaster

Bunun için teşekkürler. Sadece azaltmak sonra eksik braketi düzeltebilirsiniz:function arrayMax(array) { return array.reduce(function(a, b) { return Math.max(a, b); }); // <--------- missing ) }
Arkowsky

1
@DanielDietrich Eşdeğer yapmak, değer Math.min()olmadan çağırmak sanırım Infinity, bu nedenle bu işlevler reduce(..., Infinity)bu davranışı eşleştirmek için kullanabilirsiniz . Ben boş bir dizi minimum alarak bir hata gibi görünüyor çünkü (şu anda olduğu gibi) bir istisna atmak için tercih ederim.
Daniel Buckmaster

1
şimdiye kadar azaltmak en yavaş olanıdır.
Алексей Лещук

40

.apply genellikle amaç, argüman değerleri listesiyle birlikte değişken bir işlevi çağırmak için kullanılır;

Math.max([value1[,value2, ...]])Fonksiyon sıfır veya daha fazla sayı büyük döndürür.

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

Math.max()Yöntemi Bir dizide geçmesine izin vermez. En büyük değeri almanız gereken değerlerin bir listesine sahipseniz, normalde bu işlevi Function.prototype.apply () kullanarak çağırırsınız ;

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

Ancak, ECMAScript 6'dan itibaren spread operatörünü kullanabilirsiniz :

Forma işleci, bir ifadenin (işlev çağrıları için) veya birden çok öğenin (dizi değişmezleri için) beklendiği yerlerde bir ifadenin genişletilmesine izin verir.

Forma operatörünü kullanarak, yukarıdaki gibi yeniden yazılabilir:

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

Variadic operatörünü kullanarak bir işlevi çağırırken, ek değerler de ekleyebilirsiniz, örn.

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

Bonus:

Yayılması operatörü bir arada kullanarak, sen ES5 size zorunlu koduna geri düşmek gerekir durumlarda yeni diziler oluşturmak için dizi değişmez sözdizimini kullanmanızı sağlar push, splicevb

let foo = ['b', 'c'];
let bar = ['a', ...foo, 'd', 'e']; // ['a', 'b', 'c', 'd', 'e']

1
Bonustaki son örneğiniz concatçoğu programcı tarafından yazılır çünkü tek bir çizgi stili korumanıza izin verir.
Cody Allan Taylor

31

İki yol daha kısa ve kolaydır:

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

Yol 1 :

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

Yol 2 :

let max = arr.reduce(function(a, b) {
    return Math.max(a, b);
});

Dizinin boş olup olmadığına dikkat edin - istediğiniz şey olmayan negatif sonsuzluk elde edersiniz. Almak 0istiyorsanız veya kullanabilirsiniz ('arr' yerine) [0].concat(arr)yayılmış sözdizimi ile[0, ...arr]
Simon_Weaver

1. Değer'de null değerleri hariç tutmanın bir yolu var mı?
bonbon.langes

22

Dizi türünü genişleterek yaparsınız:

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

Dan Boosted burada (John Resig tarafından)


20

Bir Arrayöğenin üzerindeki minimum değeri bulmak için basit bir çözüm , Arrayprototip işlevini kullanmaktır reduce:

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

veya JavaScript'in yerleşik Math.Min () işlevini kullanarak (teşekkürler @Tenflex):

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

Bu kümeler miniçin A[0]daha sonra ve denetler A[1]...A[n]o kesinlikle daha az akımından daha olup olmadığı min. Eğer A[i] < minöyleyse minolarak güncellenir A[i]. Tüm dizi elemanları işlendiğinde, minsonuç olarak döndürülür.

DÜZENLEME : Minimum değerin konumunu ekleyin:

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 }

3
A. indirgeme ((min, val) => Math.min (min, val), A [0]); daha da kısa
Tenflex

Bir bonus soru olarak, sadece mindeğerin değil, aynı zamanda Array'daki pozisyonunun nasıl döndürüleceği?
stevek

@meshfields - Cevabı güncelledim.
Nicolas Lykke Iversen

15

Diğerleri zaten arttıkları bazı çözümler verdiler Array.prototype. Bu yanıt olarak bakıldığında Talep olması gerekmediğini açıklığa kavuşturmak için Math.min.apply( Math, array )veya Math.min.apply( null, array ). Peki hangi bağlam kullanılmalı, Mathya da null?

nullBağlam olarak geçerkenapply iletilirken, bağlam varsayılan olarak genel nesneye ( windowtarayıcılardaki nesne) ayarlanacaktır. Geçme Mathbağlam olarak nesneyi doğru çözüm olacaktır, ancak geçen acıtmayacak nullya. İşlevi nulldekore ederken soruna neden olabileceği bir örnek Math.max:

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

Yukarıdaki bir istisna atar çünkü this.foo olarak değerlendirilecek window.fooolan undefined. Biz değiştirirseniz nullile Mathbeklenen ve dize "foo" ekrana basılacaktır olarak işler çalışacaktır (bu kullanılarak test Mozilla Rhino ).

Kimsenin süslemediğini varsayabilirsin Math.maxnull etmediğini , geçmenin sorunsuz çalışacağını .


2
Alınan nokta. Peki neden birisi süsleyip Foo.staticMethodreferans olsun ki this? Dekoratörün tasarımında bu bir hata olmaz mı? (tabii ki sürece isteyen küresel kapsamını başvurmak ve istediğiniz gibi Rhino, kullanılan JavaScript motoru bağımsız kalması).
Roatin Marth

1
Spesifikasyon , hangi spesifik fonksiyonların " bu değer" e başvurması gerektiği konusunda açıktır (aslında, bu ifade spesifikasyonda 125 kez görünür). Math.max, özellik başına uygulanır, kullanmaz this. Birisi Math.maxkullanacağı şekilde geçersiz thiskılarsa, davranışını spesifikasyonları ihlal ettiler ve onlara keskin nesneler atmalısınız. Sen artık birilerinin takas ettiğini olasılığını etrafında kodlayacağınıza daha ihtimaline etrafında kod olmamalı Math.maxve Math.minlulz için.
Mark Amery

15

Bunu yapmanın bir yolu daha:

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

Kullanımı:

var max = arrayMax([2, 5, 1]);

Birisi bunun nasıl çalıştığını açıklayabilir mi? Bu oldukça uyuşturucu. Anladığım doğru mu: arrayMax bir işlevdir ve prototipinin bir özelliğine bir şey bağlarız mı? Bu nedir. Bind ve her prototipte var mı?
Sam


14

Alternatif yöntemler


Math.minVe Math.maxyöntemler hem JS motorun çağrı yığınına eklenen bu özyinelemeli işlemleri ve büyük olasılıkla çarpışma öğeleri çok sayıda içeren bir dizi için
(daha ~ 10⁷ öğeler yerine, kullanıcının tarayıcısında bağlıdır).

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

Yakalanmamış RangeError: Maksimum çağrı yığını boyutu aşıldı

Bunun yerine, şöyle bir şey kullanın:

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

Veya daha iyi çalışma süresiyle:

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

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

Veya hem Min hem de Maks.

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

Veya daha iyi çalışma süresiyle *:

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

* 1.000.000 öğe ile test edilmiştir:
Sadece bir referans için, 1. işlev çalışma süresi (makinemde) 15.84ms ve 2. işlev yerine sadece 4.32ms idi.


13

Bu sizin amacınıza uygun olabilir.

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

0'dan küçük bir sayı olmaması durumunda
v'nizi

Is comparerbazı özel kapsamında çağrılacak gerekiyordu? Gibi referanslar olduğu için this[index]hangi undefinedher.
Roatin Marth

Sabit, her zaman fonksiyon seviyesi kapsam belirlemeyi unuturum.
ChaosPandion

Oh, şimdi @Ionut G. Stan, varsayılan karşılaştırıcı ( Math.xxx) küresel kapsamda çalışacağından , beni yaptığı gibi aynı "yanlış bağlam" argümanı için eleştirecek ...
Roatin Marth

Bu doğru olabilir, ancak yeni işlev imzası, karşılaştırılması gereken 2 nesneyi gerektirdiğinden kapsam gerektirmez.
ChaosPandion


12

Şaşırmadım ve azaltma fonksiyonu.

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]

Unutmayın:
IE9'dan

1
Bunu Chromium'un mevcut sürümünde kullanamıyorum.
PJSCopeland

9

Büyük diziler için (~ 10⁷ elemanlar) Math.minveMath.max 10⁷ düğümde bir RangeError (Maksimum çağrı yığını boyutu aşıldı) üretir.

Büyük diziler için hızlı ve kirli bir çözüm:

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

8

Aynı sorunu yaşadım, bir dizinin minimum ve maksimum değerlerini elde etmek zorunda kaldım ve sürprizime göre diziler için yerleşik işlevler yoktu. Çok okuduktan sonra, "ilk 3" çözümleri kendim test etmeye karar verdim:

  1. ayrık çözüm: dizinin her elemanını mevcut maks ve / veya min değerine göre kontrol etmek için bir FOR döngüsü;
  2. UYGULAMA çözümü: diziyi uygula (null, dizi) kullanarak Math.max ve / veya Math.min dahili işlevlerine gönderme;
  3. REDUCE çözümü: reduce (function) işlevini kullanarak dizinin her öğesine karşı bir kontrolün tekrarlanması.

Test kodu şuydu:

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

A dizisi 100.000 rasgele tamsayı ile dolduruldu, her işlev Windows Vista ile bir Intel Pentium 4 2.99GHz masaüstünde Mozilla Firefox 28.0'da 10.000 kez yürütüldü. Süreler, performance.now () işlevi tarafından alınan saniye cinsindendir. Sonuçlar, 3 kesirli basamak ve standart sapma ile bunlardı:

  1. Ayrık çözelti: ortalama = 0.161s, sd = 0.078
  2. UYGULAMA çözümü: ortalama = 3.571s, sd = 0.487
  3. REDÜCE çözümü: ortalama = 0.350s, sd = 0.044

REDUCE çözeltisi, ayrı çözeltiden% 117 daha yavaştı. APPLY çözeltisi, ayrı çözeltiden daha kötü,% 2,118 daha yavaştı. Ayrıca, Peter'ın gözlemlediği gibi, büyük diziler (yaklaşık 1.000.000 elementten fazla) için çalışmaz.

Ayrıca, testleri tamamlamak için bu genişletilmiş ayrık kodu test ettim:

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

Zamanlama: ortalama = 0.218s, sd = 0.094

Bu nedenle, basit ayrık çözümden% 35 daha yavaştır, ancak aynı anda hem maksimum hem de minimum değerleri alır (başka herhangi bir çözüm, bunları almak için en az iki kez alır). OP her iki değere ihtiyaç duyduğunda, ayrık çözüm en iyi seçim olacaktır (biri maksimum hesaplamak için diğeri minimum hesaplamak için iki ayrı işlev olsa bile, ikinci en iyi, REDUCE çözümünden daha iyi performans gösterecektir).


8

Projenizde herhangi bir yerde aşağıdaki işlevi kullanabilirsiniz:

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

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

Ve sonra diziyi geçen işlevleri çağırabilirsiniz:

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

8

Aşağıdaki kod benim için çalışıyor:

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

7

İlerleyin, ilerledikçe takip edin.

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

Dizide hiçbir öğe yoksa, min / max null değerini bırakır. Dizide herhangi bir öğe varsa, bir geçişte min ve maks değerini ayarlar.

Array'ı, rangeyeniden kullanılabilirliğe ve yeniden okunabilirliğe izin vermek için yukarıdakileri kullanarak bir yöntemle genişletebilirsiniz . Bir çalışma keman bakın 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 }
};

Olarak kullanılır

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

var range = arr.range();

console.log(range.min);
console.log(range.max);

@JordanDillonChapian Kabul ediyorum, ancak cevabımı güncelleyerek yaptığım gibi bunu rangehem min hem de maks. IMO elde etmenin en iyi yolu olacak bir işleve genişletmek önemsiz olurdu.
tvanfosson

6

Basit ve kolay anlaşılır çözümümü paylaşacağımı düşündüm.

Min için:

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

Ve maks. İçin:

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



Teşekkürler. Cevabımı değiştirdim.
Ionut Necula

Yineleme hala yanlış (mevcut olmayan özelliklere erişme).
Bergi

Yanlış olan, yanlış bir şey görmüyorum. Lütfen bir örnek verebilir misiniz?
Ionut Necula

1
Şimdi buna göre değiştirildi. Umarım seni doğru anladım.
Ionut Necula

6

Math işlev max ve min'in yanı sıra, kullanılacak başka bir işlev de sort () işlevinin yerleşik işlevidir: işte başlıyoruz

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

5

Basit şeyler, gerçekten.

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

5

İşte bir nesne dizisinden maksimum değeri almanın bir yolu. Bir kopya oluşturun (dilim ile), ardından kopyayı azalan düzende sıralayın ve ilk öğeyi alın.

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; 

5

kullanılması Math.max()veyaMath.min()

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

Aşağıdaki işlev, Function.prototype.apply()sayısal bir dizideki maksimum öğeyi bulmak için kullanılır. getMaxOfArray([1, 2, 3])eşdeğerdir Math.max(1, 2, 3), ancak getMaxOfArray()herhangi bir boyuttaki programlı olarak oluşturulmuş dizilerde kullanabilirsiniz .

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

Ya da yeni forma operatörü ile bir dizinin maksimumu elde etmek çok daha kolay hale gelir.

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

4

Prototip kullanıyorsanız ChaosPandion'un çözümü işe yarar. Değilse, şunu düşünün:

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

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

Bir dizi değeri bir tamsayı değilse yukarıdaki NaN döndürecektir, bu nedenle bundan kaçınmak için bazı işlevler oluşturmanız gerekir. Aksi takdirde bu işe yarayacaktır.


jeerose, neden Roatin Marth (null, this) olduğunda agrument olarak (Math, this) var?
HankH

@HankH: kendi cevabımın bir yorumunda yorumunuza verdiğiniz yanıtı görün.
Roatin Marth

1
"Eğer prototip kullanıyorsanız ChaosPandion'ın çözümü işe yarıyor" ile ne demek istediğinizi anlamıyorum. MathNesneyi bağlam olarak kullanmanız dışında çözümünüz nasıl farklı ?
Ionuț G. Stan

Üzgünüm, demek istediğim seninkinin çalışacağı prototipi uzatırsan. Özür.
jay

Peki hangisi daha iyi, jeerose veya ChaosPandion's?
HankH

3

Sugar.js kütüphanesini kullanıyorsanız , önerdiğiniz gibi arr.min () ve arr.max () yazabilirsiniz . Sayısal olmayan dizilerden minimum ve maksimum değerler de alabilirsiniz.

min (map, all = false) Dizideki en düşük değere sahip öğeyi döndürür. map, denetlenecek değeri eşleştiren bir işlev veya kısayol olarak işlev gören bir dize olabilir. All doğruysa, bir dizideki tüm min değerlerini döndürür.

max (map, all = false) Dizideki en büyük değere sahip öğeyi döndürür. map, denetlenecek değeri eşleştiren bir işlev veya kısayol olarak işlev gören bir dize olabilir. Tümü true olursa, bir dizideki tüm maksimum değerleri döndürür.

Örnekler:

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

Lo-Dash ve underscore.js gibi kütüphaneler de benzer güçlü min ve maks işlevleri sağlar:

Lo-Dash'ten bir örnek:

_.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 }

3
let arr = [2,5,3,5,6,7,1];

let max = Math.max(...arr); // 7
let min = Math.min(...arr); // 1

2
Bu çözüm, bu soruya başka birden çok yanıt veren tarafından zaten sağlanmıştır. Cevabınız ne ekliyor?
Nick

3

Deneyin

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

Math.min / max (+ uygulamak) için hata alırız:

Maksimum çağrı yığını boyutu aşıldı (Chrome 74.0.3729.131)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.