Bagaimana menemukan indeks dari semua kemunculan elemen dalam array?


108

Saya mencoba menemukan indeks dari semua contoh elemen, katakanlah, "Nano", dalam array JavaScript.

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

Saya mencoba jQuery.inArray , atau serupa, .indexOf () , tetapi hanya memberikan indeks contoh terakhir elemen, yaitu 5 dalam kasus ini.

Bagaimana cara mendapatkannya untuk semua contoh?

Jawaban:


115

The .indexOf()metode memiliki parameter opsional kedua yang menentukan indeks untuk memulai pencarian dari, sehingga Anda dapat menyebutnya dalam satu lingkaran untuk menemukan semua contoh nilai tertentu:

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

Anda tidak benar-benar memperjelas bagaimana Anda ingin menggunakan indeks, jadi fungsi saya mengembalikannya sebagai array (atau mengembalikan array kosong jika nilainya tidak ditemukan), tetapi Anda dapat melakukan sesuatu yang lain dengan nilai indeks individual di dalam lingkaran.

PEMBARUAN: Sesuai komentar VisioN, perulangan for yang sederhana akan menyelesaikan pekerjaan yang sama dengan lebih efisien, dan lebih mudah untuk dipahami dan karena itu lebih mudah untuk dipelihara:

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

1
Tampaknya ini bukan alternatif yang lebih cepat untuk satu forloop dengan array indeks yang terisi.
VisioN

1
@VisioN - Ya, sebuah dataran untuk pengulangan loop pada array akan lebih sederhana juga, tetapi karena OP menyebutkan mencoba menggunakan .indexOf()saya ingin menunjukkan bahwa itu dapat melakukan pekerjaan itu. (Saya kira saya pikir OP bisa mengetahui bagaimana melakukannya dengan for loop.) Tentu saja ada cara lain untuk melakukannya, misalnya,Cars.reduce(function(a, v, i) { if (v==="Nano") a.push(i); return a; }, []);
nnnnnn

Saya dapat memberitahu Anda dari Amerika Utara karena Anda menggunakan indexesbukannya indices: P
4castle

2
@ 4castle - Ha. Tidak, bukan aku. "Indeks" dan "indeks" sama-sama benar, dan saya cenderung bergantian di antara keduanya. Saya tidak pernah menganggap itu sebagai dialek daerah. Menarik.
nnnnnn

Perhatikan bahwa contoh pertama yang diberikan berfungsi dengan baik untuk string dan array. Yang kedua hanya berfungsi untuk array.
SethWhite

81

Solusi alternatif lain adalah dengan menggunakan 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]

NB: Periksa kompatibilitas browser untuk reducemetode dan gunakan polyfill jika diperlukan.


2
+1. Kebetulan yang lucu: Saya baru saja mengedit balasan saya untuk komentar Anda di bawah jawaban saya untuk menyarankan solusi ini dengan tepat, lalu saya menyegarkan dan melihat Anda sudah mengkodekan hal yang sama dengan hanya satu nama variabel yang berbeda.
nnnnnn

@nnnnnn :)Ya, saya pikir mungkin reducebisa menjadi alternatif yang bagus.
VisioN

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

Saya googled contatlebih lambat dari push, oleh karena itu saya tetap dengan jawabannya.
Andre Elrico

54

Pendekatan lain menggunakan Array.prototype.map () dan Array.prototype.filter () :

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

3
bagus, itu berhasil. dapatkah Anda menjelaskan apa peran filter (String)
Muthamizhchelvan. V

2
@Muthu map(…)memeriksa setiap iterasi untuk persamaan edan value. Ketika mereka cocok, indeks dikembalikan, jika tidak, string kosong. Untuk menghilangkan nilai falsy tersebut, filter(String)pastikan bahwa hasil hanya berisi nilai yang bertipe string dan BUKAN kosong. filter(String)dapat juga ditulis sebagai:filter(e => e !== '')
yckart

3
... atau: String(thing)memaksa apapun menjadi sebuah string. Array#filtermengembalikan sebuah array dari semua nilai-nilai yang kondisinya truthy . Karena string kosong adalah falsy , mereka TIDAK termasuk dalam array.
yckart

Terima kasih atas penjelasan Anda, ini sangat membantu saya
Muthamizhchelvan. V

2
Saya akan bingung jika melihat ini dalam sebuah proyek. Bunyinya seperti "Filter ke string", artinya hanya disimpan jika itu adalah string. Dan kemudian array yang dihasilkan akan menjadi indeks sebagai string, bukan angka.
Michael Pearson

14

Cara yang lebih sederhana dengan gaya es6.

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

Anda dapat menulis solusi sederhana yang dapat dibaca untuk ini dengan menggunakan mapdan filter:

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

EDIT: Jika Anda tidak perlu mendukung IE / Edge (atau mentransformasikan kode Anda), ES2019 memberi kami flatMap , yang memungkinkan Anda melakukan ini dalam satu baris sederhana:

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

6

Catatan: MDN memberikan metode menggunakan while loop :

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

Saya tidak akan mengatakan itu lebih baik dari jawaban lain. Menarik saja.


4

Saya hanya ingin memperbarui dengan metode lain yang mudah.

Anda juga dapat menggunakan metode forEach.

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
Indeks berbasis nol, jadi ini akan gagal jika mobil pertama adalah Nano.
Zac Delventhal

1
Oh, lihat, Anda punya solusinya dan solusi saya sepertinya cocok. Aku seharusnya melihat milikmu sebelum aku menghabiskan waktu menulis milikku. Ada begitu banyak putaran untuk putaran, saya pikir, "Saya bisa membuat jawaban sendiri dalam 2 detik."
Michael Pearson

Ya. Ini sebagian besar terlalu rumit. Koreksi yang bagus.
Zac Delventhal

2

Ini berhasil untuk saya:

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

Hanya untuk membagikan metode lain, Anda dapat menggunakan Generator Fungsi untuk mendapatkan hasilnya juga:

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

Kita bisa menggunakan Stack dan mendorong "i" ke dalam stack setiap kali kita menemukan kondisi "arr [i] == value"

Periksa ini:

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
Pertanyaannya ditandai dengan javascript, sedangkan jawaban Anda adalah Javasaya percaya?
noggin182

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

=> [0, 2]

Harap tulis penjelasan penting atau komentar sebaris untuk kode tersebut. BTW, solusi Anda berhasil tetapi berisi 3 iterasi ...
JustWe

0

Anda dapat menggunakan Polyfill

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

}

Gunakan seperti ini:

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

result: [0, 3, 7]

-1

findIndexhanya mengambil indeks pertama yang cocok dengan keluaran callback. Anda dapat menerapkannya sendiri findIndexesdengan memperluas Array, lalu mentransmisikan array Anda ke struktur baru.

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

Jika Anda berniat menggunakan garis bawah / lodash, Anda bisa melakukannya

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
Anda tidak benar-benar membutuhkan perpustakaan untuk itu:(["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"]).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0])
edjroot
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.