配列内のすべての要素のインデックスを見つける方法は?


108

JavaScript配列で、要素のすべてのインスタンスのインデックス(「Nano」など)を見つけようとしています。

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

私はjQuery.inArrayまたは同様に.indexOf()を試しましたが、要素の最後のインスタンスのインデックス(この場合は5 しか与えられませんでした。

すべてのインスタンスでどのように取得できますか?

回答:


115

この.indexOf()メソッドには、検索を開始するインデックスを指定するオプションの2番目のパラメーターがあるため、ループでそれを呼び出して、特定の値のすべてのインスタンスを見つけることができます。

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

インデックスの使用方法を明確にしていないため、関数はそれらを配列として返します(または、値が見つからない場合は空の配列を返します)が、個々のインデックス値を使用して別のことを行うことができますループの内側。

更新:VisioNのコメントによると、単純なforループは同じ仕事をより効率的に実行し、理解しやすく、したがって保守が容易になります。

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

1
これはfor、インデックス配列にデータを入力する単一のループに代わる高速な方法ではないようです。
VisioN

1
@VisioN-はい、配列を繰り返し処理する単純なforループの方が単純ですが、OPが使用しようとしている.indexOf()と述べたので、それが機能することを示したかったのです。(私は、OPがforループでそれを行う方法を理解できると思いました。)もちろん、他の方法もあります。たとえば、Cars.reduce(function(a, v, i) { if (v==="Nano") a.push(i); return a; }, []);
nnnnnn

私はあなたが使用しているため、あなたが北米からだ伝えることができますindexes代わりにindicesP:
4castle

2
@ 4castle-ハ。いいえ、違います。「インデックス」と「インデックス」はどちらも正しいので、私は2つを交互に使用する傾向があります。地域の方言だとは思っていませんでした。面白い。
nnnnnn

与えられた最初の例は文字列と配列に適していることに注意してください。2番目は、配列に対してのみ機能します。
SethWhite 2018

80

別の代替ソリューションは、使用すること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]

注意:メソッドのブラウザ互換性を確認し、必要に応じてポリフィルreduceを使用してください


2
+1。おかしい偶然:私はちょうど私の答えの下であなたのコメントへの私の返事を編集してちょうどこの解決策を提案しました、そして私はリフレッシュして、1つだけ異なる変数名で同じことをすでにコーディングしているのを確認します。
nnnnnn

@nnnnnn :)ええ、私はおそらくreduce良い代替案になると思いました。
VisioN

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

私はグーグルcontatが遅いpushので、答えに固執します。
Andre Elrico

54

Array.prototype.map()およびArray.prototype.filter()を使用した別のアプローチ:

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

3
すばらしいです。フィルター(String)の役割は何かを説明できますか
Muthamizhchelvan。V

2
@Muthuのmap(…)平等のための各反復でチェックeしてvalue。それらがインデックスと一致する場合は返され、それ以外の場合は空の文字列です。これらの偽の値を取り除くにはfilter(String)、結果に文字列型の値のみが含まれ、空ではないことを確認してください。filter(String):のように書くこともできたfilter(e => e !== '')
yckart

3
...または:String(thing)文字列を強制します。Array#filter条件がであるすべての値の配列を返します。空の文字列はfalsyであるため、配列には含まれません。
yckart 2018年

ご説明いただきありがとうございます、それは私にとって本当に便利です
Muthamizhchelvan。V

2
これをプロジェクトで見た場合、混乱します。「文字列にフィルタ」のように読みます。つまり、文字列である場合にのみ保持します。そして、結果の配列は、数値ではなく文字列としてのインデックスになります。
マイケルピアソン、

14

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

mapとの両方を使用して、これに対する簡単で読み取り可能なソリューションを作成できますfilter

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

編集:IE / Edgeをサポートする必要がない場合(またはコードをトランスパイルしている場合)、ES2019から提供されたflatMapを使用すると、簡単な1 でこれを実行できます。

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


4

別の簡単な方法で更新したいだけです。

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
インデックスはゼロベースなので、最初の車がNanoの場合は失敗します。
Zac Delventhal

1
ああ、あなたには解決策があり、私のように見えます。私が私の執筆に時間を費やす前に、私はあなたのものを見るべきでした。「2秒で自分の答えが出せる」と思ったループが無数に広がっていました。
マイケルピアソン、

うん。これらはほとんどが非常に複雑です。素敵な修正。
Zac Delventhal

2

これは私のために働きました:

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

別の方法を共有するために、関数ジェネレーターを使用して結果を取得することもできます。

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

スタックを使用して、条件「arr [i] == value」に遭遇するたびに「i」をスタックにプッシュできます。

これをチェックして:

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
質問はでタグ付けされてjavascriptいますが、あなたの答えはJava私が信じていますか?
noggin182

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

=> [0, 2]

コードの重要な説明またはインラインコメントを書き込んでください。ところで、あなたのソリューションは機能しましたが、3つの反復が含まれています...
JustWe

0

ポリフィルを使用できます

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

}

次のように使用します。

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

result: [0, 3, 7]

-1

findIndexコールバック出力に一致する最初のインデックスのみを取得します。findIndexesArrayを拡張して独自の配列を実装し、配列を新しい構造にキャストできます。

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

アンダースコア/ロダッシュを使用する場合は、次のようにすることができます

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
そのためのライブラリは本当に必要ありません。 (["Nano", "Volvo", "BMW", "Nano", "VW", "Nano"]).map((v, i)=> [i, v === "Nano"]).filter(v=>v[1]).map(v=>v[0])
edjroot
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.