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?

norbdum
sumber

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;
}
nnnnnn
sumber
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.

Penglihatan
sumber
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)
yckart
sumber
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); // []
Mikhail Gorelyshev
sumber
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 : []);
Zac Delventhal
sumber
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.

abalter
sumber
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)
Ted Khi
sumber
3
const indexes = cars
    .map((car, i) => car === "Nano" ? i : null)
    .filter(i => i !== null)
Michael Pearson
sumber
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]
Jona Dev
sumber
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'));

briosheje
sumber
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(); 
    }
}
S Banzal
sumber
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]
Dávid Konkoly
sumber
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]
EbiPenMan
sumber
-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'))
)

Abdennour TOUMI
sumber
-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]
Nol
sumber
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