Dizideki öğelerin tüm oluşumlarının indeksi nasıl bulunur?


108

JavaScript dizisindeki bir elemanın tüm örneklerinin, örneğin "Nano" dizinini bulmaya çalışıyorum.

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];

JQuery.inArray veya benzer şekilde .indexOf () denedim , ancak bu yalnızca öğenin son örneğinin dizinini, yani bu durumda 5 verdi.

Tüm örnekler için nasıl edinebilirim?

Yanıtlar:


116

.indexOf()Yöntem , belirli bir değerin tüm örneklerini bulmak için bir döngü içinde diyoruz böylece belirtir endeksi aramaya başlamak zorunda olduğunu opsiyonel ikinci parametresi vardır:

function getAllIndexes(arr, val) {
    var indexes = [], i = -1;
    while ((i = arr.indexOf(val, i+1)) != -1){
        indexes.push(i);
    }
    return indexes;
}

var indexes = getAllIndexes(Cars, "Nano");

Dizinleri nasıl kullanmak istediğinizi gerçekten netleştirmiyorsunuz, bu nedenle işlevim onları bir dizi olarak döndürüyor (veya değer bulunamazsa boş bir dizi döndürüyor), ancak tek tek dizin değerleriyle başka bir şey yapabilirsiniz. döngünün içinde.

GÜNCELLEME: VisioN'un yorumuna göre, basit bir for döngüsü aynı işi daha verimli bir şekilde yapacaktır ve anlaşılması ve dolayısıyla bakımı daha kolaydır:

function getAllIndexes(arr, val) {
    var indexes = [], i;
    for(i = 0; i < arr.length; i++)
        if (arr[i] === val)
            indexes.push(i);
    return indexes;
}

1
forDizin dizisi doldurulan tek bir döngüye daha hızlı bir alternatif gibi görünmüyor .
VisioN

1
@VisioN - Evet, dizi üzerinde yinelenen düz bir döngü de daha basit olurdu, ancak OP kullanmaya çalıştığından bahsettiğinden .indexOf(), işi yapabileceğini göstermek istedim. (Ben OP döngü için birlikte nasıl yapılacağını anlamaya düşündüm sanırım.) Tabii ki bunu yapmak için başka yollar, örneğin vardırCars.reduce(function(a, v, i) { if (v==="Nano") a.push(i); return a; }, []);
nnnnnn

Kuzey Amerika'dan olduğunu söyleyebilirim çünkü indexesbunun yerine şunu kullandın indices: P
4castle 14'16

2
@ 4castle - Ha. Hayır, değilim. "Endeksler" ve "indeksler" her ikisi de doğrudur ve ben ikisi arasında gidip geliyorum. Bunu bölgesel bir lehçe olarak hiç düşünmemiştim. İlginç.
nnnnnn

Verilen ilk örneğin dizeler ve diziler için harika çalıştığını unutmayın. İkincisi yalnızca diziler için çalışır.
SethWhite

81

Başka bir alternatif çözüm kullanmaktır Array.prototype.reduce():

["Nano","Volvo","BMW","Nano","VW","Nano"].reduce(function(a, e, i) {
    if (e === 'Nano')
        a.push(i);
    return a;
}, []);   // [0, 3, 5]

Not: Kontrol tarayıcı uyumluluğu için reduceyöntem ve kullanım Polyfill gerekirse.


2
+1. Komik tesadüf: Tam olarak bu çözümü önermek için cevabımın altındaki yorumunuza verdiğim yanıtı düzenledim, sonra tazeliyorum ve aynı şeyi zaten farklı bir değişken adıyla kodladığınızı görüyorum.
nnnnnn

@nnnnnn :)Evet, reducegüzel bir alternatif olabileceğini düşündüm .
VisioN

26
array.reduce((a, e, i) => (e === value) ? a.concat(i) : a, [])
yckart

Googled contatdaha yavaş push, bu yüzden cevaba sadık kaldım.
Andre Elrico

54

Array.prototype.map () ve Array.prototype.filter () kullanan başka bir yaklaşım :

var indices = array.map((e, i) => e === value ? i : '').filter(String)

3
harika, işe yarıyor. filtrenin (String)
Muthamizhchelvan

2
@Muthu map(…), eve eşitliği için her yinelemede kontrol eder value. Dizinle eşleştiklerinde döndürülür, aksi takdirde boş bir dize. Bu hatalı değerlerden kurtulmak filter(String)için, sonucun yalnızca dizge türü olan ve boş DEĞİL değerleri içerdiğinden emin olun. filter(String)şu şekilde de yazılabilir:filter(e => e !== '')
yckart

3
... veya: String(thing)herhangi bir şeyi bir dizeye zorlar. Array#filterkoşul olan değerleri her bir dizi döner truthy . Boş dizeler yanlış olduğundan , bunlar diziye dahil DEĞİLDİR.
yckart

Açıklamanız için teşekkür ederim, benim için gerçekten yardımcı oluyor
Muthamizhchelvan. V

2
Bunu bir projede görürsem kafam karışır. "Dizelere filtre uygula" gibi okur, yani yalnızca bir dizeyse sakla anlamına gelir. Ve sonra ortaya çıkan dizi sayılar değil dizeler olarak dizinler olacaktır.
Michael Pearson

14

Es6 stili ile daha basit bir yol.

const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);


//Examples:
var cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];
indexOfAll(cars, "Nano"); //[0, 3, 5]
indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3]
indexOfAll([1, 2, 3], 4); // []

12

Hem mapve hem de kullanarak buna basit ve okunabilir bir çözüm yazabilirsiniz filter:

const nanoIndexes = Cars
  .map((car, i) => car === 'Nano' ? i : -1)
  .filter(index => index !== -1);

DÜZENLEME: IE / Edge'i desteklemeniz gerekmiyorsa (veya kodunuzu aktarıyorsanız), ES2019 bize bunu basit bir tek satırda yapmanızı sağlayan flatMap'i verdi :

const nanoIndexes = Cars.flatMap((car, i) => car === 'Nano' ? i : []);

6

Not: MDN, while döngüsü kullanan bir yöntem verir :

var indices = [];
var array = ['a', 'b', 'a', 'c', 'a', 'd'];
var element = 'a';
var idx = array.indexOf(element);
while (idx != -1) {
  indices.push(idx);
  idx = array.indexOf(element, idx + 1);
}

Diğer cevaplardan daha iyi olduğunu söyleyemem. Sadece ilginç.


4

Sadece başka bir kolay yöntemle güncellemek istiyorum.

Ayrıca forEach yöntemini de kullanabilirsiniz.

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];

var result = [];

Cars.forEach((car, index) => car === 'Nano' ? result.push(index) : null)

3
const indexes = cars
    .map((car, i) => car === "Nano" ? i : null)
    .filter(i => i !== null)

1
Dizinler sıfır tabanlıdır, bu nedenle ilk araba bir Nano ise bu başarısız olacaktır.
Zac Delventhal

1
Oh bak, bir çözümün var ve benimki de buna benziyor. Benimkini yazmaya zaman harcamadan önce seninkini görmeliydim. Döngüler için o kadar çok yayılmıştı ki, "2 saniyede kendi cevabımı verebilirim" diye düşündüm.
Michael Pearson

Evet. Bunlar çoğunlukla aşırı karmaşıktır. Güzel düzeltme.
Zac Delventhal

2

Bu benim için çalıştı:

let array1 = [5, 12, 8, 130, 44, 12, 45, 12, 56];
let numToFind = 12
let indexesOf12 = [] // the number whose occurrence in the array we want to find

array1.forEach(function(elem, index, array) {
    if (elem === numToFind) {indexesOf12.push(index)}
    return indexesOf12
})

console.log(indexesOf12) // outputs [1, 5, 7]

1

Sadece başka bir yöntemi paylaşmak için, sonuca ulaşmak için İşlev Oluşturucuları da kullanabilirsiniz :

function findAllIndexOf(target, needle) {
  return [].concat(...(function*(){
    for (var i = 0; i < target.length; i++) if (target[i] === needle) yield [i];
  })());
}

var target = "hellooooo";
var target2 = ['w','o',1,3,'l','o'];

console.log(findAllIndexOf(target, 'o'));
console.log(findAllIndexOf(target2, 'o'));


0

Yığını kullanabilir ve "dizi [i] == değer" koşuluyla her karşılaştığımızda yığına "i" gönderebiliriz

Şuna göz at:

static void getindex(int arr[], int value)
{
    Stack<Integer>st= new Stack<Integer>();
    int n= arr.length;
    for(int i=n-1; i>=0 ;i--)
    {
        if(arr[i]==value)
        {
            st.push(i);
        }
    }   
    while(!st.isEmpty())
    {
        System.out.println(st.peek()+" ");
        st.pop(); 
    }
}

2
Sorunun javascriptetiketinde, cevabına Javainanıyorum.
noggin182

0
["a", "b", "a", "b"]
   .map((val, index) => ({ val, index }))
   .filter(({val, index}) => val === "a")
   .map(({val, index}) => index)

=> [0, 2]

Lütfen kod için önemli bir açıklama veya satır içi yorumlar yazın. BTW, çözümünüz işe yaradı ama 3 yineleme içeriyor ...
JustWe

0

Polyfill'i kullanabilirsiniz

if (!Array.prototype.filterIndex) {
Array.prototype.filterIndex = function (func, thisArg) {

    'use strict';
    if (!((typeof func === 'Function' || typeof func === 'function') && this))
        throw new TypeError();

    let len = this.length >>> 0,
        res = new Array(len), // preallocate array
        t = this, c = 0, i = -1;

    let kValue;
    if (thisArg === undefined) {
        while (++i !== len) {
            // checks to see if the key was set
            if (i in this) {
                kValue = t[i]; // in case t is changed in callback
                if (func(t[i], i, t)) {
                    res[c++] = i;
                }
            }
        }
    }
    else {
        while (++i !== len) {
            // checks to see if the key was set
            if (i in this) {
                kValue = t[i];
                if (func.call(thisArg, t[i], i, t)) {
                    res[c++] = i;
                }
            }
        }
    }

    res.length = c; // shrink down array to proper size
    return res;
};

}

Bunu şu şekilde kullanın:

[2,23,1,2,3,4,52,2].filterIndex(element => element === 2)

result: [0, 3, 7]

-1

findIndexyalnızca geri arama çıktısıyla eşleşen ilk dizini alır. Kendi uygulayabilirsiniz findIndexessonra yeni yapıya da dizileri döküm, Diziyi uzatarak.

class EnhancedArray extends Array {
  findIndexes(where) {
    return this.reduce((a, e, i) => (where(e, i) ? a.concat(i) : a), []);
  }
}
   /*----Working with simple data structure (array of numbers) ---*/

//existing array
let myArray = [1, 3, 5, 5, 4, 5];

//cast it :
myArray = new EnhancedArray(...myArray);

//run
console.log(
   myArray.findIndexes((e) => e===5)
)
/*----Working with Array of complex items structure-*/

let arr = [{name: 'Ahmed'}, {name: 'Rami'}, {name: 'Abdennour'}];

arr= new EnhancedArray(...arr);


console.log(
  arr.findIndexes((o) => o.name.startsWith('A'))
)


-1

Alt çizgi / lodash kullanmayı düşünüyorsanız, şunları yapabilirsiniz:

var Cars = ["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"];

_.chain(Cars).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0]).value()

[0, 3, 5]

2
Bunun için gerçekten herhangi bir kitaplığa ihtiyacınız yok:(["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"]).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0])
edjroot
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.