Bir dizideki en büyük değerin dönüş dizini


139

Bu bende var:

var arr = [0, 21, 22, 7];

En yüksek değerin dizinini başka bir değişkene döndürmenin en iyi yolu nedir?


21
Bu bir kopya değil, soruyu okuyun… @Dancrumb SO'nun çalışma şekli, bu soruyu gönderiyorum ve gelecek on yıllar boyunca insanlar onu bulacak, okuyacak ve katkıda bulunanların aşağıya gönderdiği bilgiler için minnettar olacaklar!
Stephen

1
@Stephen, tam tersine, bu SSS'yi okursanız , öznel soruların ("En iyi yol nedir ..." ile başlayanlar gibi) açıkça cesaretinin kırıldığını göreceksiniz. Bununla birlikte, SO bir topluluktur, bu nedenle bu sorunun kapatılıp kapatılmayacağına topluluk karar verir.
Dancrumb

6
Bir dizideki en büyük sayıyı bulmak, bir dizideki en büyük sayının dizinini bulmakla aynı şey değildir. Bu nedenle, bu soru, kopya olarak gönderilen referansın bir kopyası değildir.
Fzs2

15
Bu bir kopya DEĞİL - veya en azından başvurulan sorunun bir kopyası değildir. Bu konudaki olumsuz oyları anlayamıyorum - SO'dan soramayacağınızı söylemek bir şeyi yapmanın en iyi yolu gülünçtür ve böylesine kısa bir soru için kod örneği gerekmez. Nasıl oluyor da atıfta bulunulan 'mükerrer' +30 oya sahip ve buna çok benzer bir tarzda sorulan bu paralel AMA FARKLI soru -3 oya sahip? Lütfen soruyu tekrar okuyun ve mükerrer olarak işaretlenmiş oylarınızı kaldırın. Soru başlığında görmeniz gereken anahtar kelime "dizini" dir.
krep

@Dancrumb stackoverflow.com/help/dont-ask adresindeki mevcut tavsiye, yalnızca her yanıtın eşit derecede geçerli olması durumunda öznel soruları caydırır. Bu durumda "en iyi", performans, açıklık ve ifade gücü açısından açıkça değerlendirilebilir.
user234461

Yanıtlar:


165

Güvenilir olduğu ve eski tarayıcılarda çalıştığı için bu muhtemelen en iyi yoldur:

function indexOfMax(arr) {
    if (arr.length === 0) {
        return -1;
    }

    var max = arr[0];
    var maxIndex = 0;

    for (var i = 1; i < arr.length; i++) {
        if (arr[i] > max) {
            maxIndex = i;
            max = arr[i];
        }
    }

    return maxIndex;
}

Bir de şu tek satırlık var:

let i = arr.indexOf(Math.max(...arr));

Gerektiğinde iki kat daha fazla karşılaştırma yapar ve yine de RangeErrorbüyük dizilere bir atar . İşleve bağlı kalırım.


1
Tamam bu işlev , en büyük değer için ilk karşılaşılan dizini döndürür . Diyelim ki aynı en yüksek değere sahip birden fazla dizinim var, tüm bu dizinleri nasıl elde ederim ?
ed1nh0

1
@ ed1nh0: Kolay yol, birden çok geçiş yapmaktır. İle maks. Bul const max = arr.reduce((m, n) => Math.max(m, n)), sonra maks [...arr.keys()].filter(i => arr[i] === max). İndeksler .
Ry-

[...arr.keys()]bir hata unexpected token
veriyor

@ ed1nh0: Hangi tarayıcıyı / ortamı hedefliyorsunuz?
Ry-

Krom. VueJS kullanıyorum ve sanırım sorun web paketi yapılandırmasında bir şey.
ed1nh0

82

Tek satırda ve muhtemelen daha hızlı arr.indexOf(Math.max.apply(Math, arr)):

var a = [0, 21, 22, 7];
var indexOfMaxValue = a.reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);

document.write("indexOfMaxValue = " + indexOfMaxValue); // prints "indexOfMaxValue = 2"

Nerede:

  • iMax- En iyi endeks bugüne kadar (birinci tekrar bugüne kadar maksimum elemanın indeksi, iMax = 0ikinci argüman çünkü reduce()olduğunu 0, biz ikinci argüman geçemeyeceğim reduce()bizim durumumuzda)
  • x - diziden şu anda test edilen öğe
  • i - şu anda test edilen indeks
  • arr- dizimiz ( [0, 21, 22, 7])

Hakkında reduce()(: David Flanagan tarafından "Kesin Kılavuzu JavaScript" dan) yöntemiyle:

azaltma () iki argüman alır. Birincisi, küçültme işlemini gerçekleştiren işlevdir. Bu indirgeme işlevinin görevi, iki değeri bir şekilde tek bir değerde birleştirmek veya azaltmak ve bu indirgenmiş değeri döndürmektir.

Low () ile kullanılan fonksiyonlar, forEach () ve map () ile kullanılan fonksiyonlardan farklıdır. Tanıdık değer, dizin ve dizi değerleri ikinci, üçüncü ve dördüncü bağımsız değişkenler olarak aktarılır. İlk argüman, şimdiye kadarki indirgemenin birikmiş sonucudur. İşleve ilk çağrıda, bu ilk bağımsız değişken, azaltma () için ikinci bağımsız değişken olarak ilettiğiniz ilk değerdir. Sonraki çağrılarda, işlevin önceki çağrısı tarafından döndürülen değerdir.

Başlangıç ​​değeri olmadan azaltma () 'yı çağırdığınızda, dizinin ilk öğesini başlangıç ​​değeri olarak kullanır. Bu, azaltma işlevine yapılan ilk çağrının, birinci ve ikinci argümanları olarak birinci ve ikinci dizi öğelerine sahip olacağı anlamına gelir.


12
@traxium Açıklamanız harika olsa da, daha açıklayıcı değişkenler kullanırsak örnek, işlevsel programlamaya daha az ilgi duyanlar için daha net olabilir. Ki: arr.reduce((bestIndexSoFar, currentlyTestedValue, currentlyTestedIndex, array) => currentlyTestedValue > array[bestIndexSoFar] ? currentlyTestedIndex : bestIndexSoFar, 0);olarak tarif edilebilir: Eğer yineleme indeksi 0 (2 parametre) başlayarak dizi currentlyTestedValue elemanını değerinden daha yüksektir bestIndexSoFar , daha sonra geri currentlyTestedIndex sonraki iterasyon için bestIndexSoFar .
niieani

1
@traxium Harika cevap. @Niieani İşte uygulanan gerçek bir dünya örneğidir ile ben de katılıyorum: this.methods.reduce((methodIndex, currentMethod, currentMethodIndex, methods) => currentMethod.price <= methods[methodIndex].price ? currentMethodIndex : methodIndex, 0).
Daniel

2
@DanielK, "Tam" parametre adlarının yanıtı tek bir yığın aşımı satırına sığmaz. Yatay bir kaydırma çubuğu görünür ve yatay olarak kaydırırken pasajı okumak pek uygun olmaz. Her neyse öneriler için teşekkürler. Cevabı başka bir şekilde düzenledim.
traxium

FP çözümü için @traxium +1. JS ile yeni başlayan biri için morbid derecede karmaşık olsa da, çözümünüz aynı zamanda OP'nin problemini çözmek için en performanslı çözümlerden biridir.
SeaWarrior404

Jsben.ch/ujXlk'ye göre diğer yöntem daha hızlıdır.
VFDan

48

İşte başka bir çözüm: Yayılma operatörünü kullanarak ES6 kullanıyorsanız:

var arr = [0, 21, 22, 7];

const indexOfMaxValue = arr.indexOf(Math.max(...arr));

6

Yanılmıyorsam, kendi fonksiyonunuzu yazmanız gerektiğini söyleyebilirim.

function findIndexOfGreatest(array) {
  var greatest;
  var indexOfGreatest;
  for (var i = 0; i < array.length; i++) {
    if (!greatest || array[i] > greatest) {
      greatest = array[i];
      indexOfGreatest = i;
    }
  }
  return indexOfGreatest;
}

6

Alt çizgi kullanıyorsanız, bu güzel kısa tek satırlık çizgiyi kullanabilirsiniz:

_.indexOf(arr, _.max(arr))

İlk önce dizideki en büyük öğenin değerini, bu durumda 22'yi bulacaktır. Daha sonra dizi içinde 22'nin bulunduğu dizini, bu durumda 2'yi döndürecektir.


6

Max kullanmanın başka bir çözümü reduce:

[1,2,5,0,4].reduce((a,b,i) => a[0] < b ? [b,i] : a, [Number.MIN_VALUE,-1])
//[5,2]

[5e-324, -1]Dizi boşsa bu döndürülür . Sadece dizini istiyorsanız, [1]sonrasına koyun .

Min aracılığıyla ( >ve Değiştir MAX_VALUE):

[1,2,5,0,4].reduce((a,b,i) => a[0] > b ? [b,i] : a, [Number.MAX_VALUE,-1])
//[0, 3]

1

DÜZENLEME: Yıllar önce buna kaba, çok özel ve çok karmaşık bir cevap verdim. Ben de düzenliyorum. Yukarıdaki işlevsel cevapları temiz faktörleri için tercih ediyorum, ancak okunabilirlikleri değil; ama javascript'e daha aşina olsaydım, onun için de hoşuma gidebilirdi.

Sözde kod:

En büyük değeri içeren izleme dizini. 0 indisinin başlangıçta en büyük olduğunu varsayalım. Mevcut endeksle karşılaştırın. Gerekirse dizini en büyük değere sahip güncelleyin.

Kod:

var mountains = [3, 1, 5, 9, 4];

function largestIndex(array){
  var counter = 1;
  var max = 0;

  for(counter; counter < array.length; counter++){
    if(array[max] < array[counter]){
        max = counter;
    }
  }
  return max;
}

console.log("index with largest value is: " +largestIndex(mountains));
// index with largest value is: 3

Teşekkürler! Daha fazla uğraşmak zorunda kaldım.
ross studtman

1
function findIndicesOf(haystack, needle)
{
    var indices = [];

    var j = 0;
    for (var i = 0; i < haystack.length; ++i) {
        if (haystack[i] == needle)
            indices[j++] = i;
    }
    return indices;
}

geçmesi arrayiçin haystackve Math.max(...array)için needle. Bu , dizinin tüm maksimum elemanlarını verir ve daha fazla genişletilebilirdir (örneğin, ayrıca minimum değerleri bulmanız gerekir)


1

Dizinin bir kopyasını oluşturur ve azalan sıralarsanız, kopyanın ilk öğesi en büyük olacaktır. Daha sonra dizinini orijinal dizide bulabilirsiniz.

var sorted = [...arr].sort((a,b) => b - a)
arr.indexOf(sorted[0])

Zaman karmaşıklığı kopya için O (n), sıralama için O (n * log (n)) ve indexOf için O (n) şeklindedir.

Daha hızlı yapmanız gerekiyorsa, Ry'nin cevabı O (n).


0

 var arr=[0,6,7,7,7];
 var largest=[0];
 //find the largest num;
 for(var i=0;i<arr.length;i++){
   var comp=(arr[i]-largest[0])>0;
      if(comp){
	  largest =[];
	  largest.push(arr[i]);
	  }
 }
 alert(largest )//7
 
 //find the index of 'arr'
 var arrIndex=[];
 for(var i=0;i<arr.length;i++){
    var comp=arr[i]-largest[0]==0;
	if(comp){
	arrIndex.push(i);
	}
 }
 alert(arrIndex);//[2,3,4]


-1

Bu işlevin kararlı bir sürümü şuna benzer:

// not defined for empty array
function max_index(elements) {
    var i = 1;
    var mi = 0;
    while (i < elements.length) {
        if (!(elements[i] < elements[mi]))
            mi = i;
        i += 1;
    }
    return mi;
}

Bu bağlamda "kararlı" ne anlama geliyor?
Ry-

Sanırım "uygun" demek istedi
Ikbel
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.