条件に一致する配列内のオブジェクトのインデックスを取得します


322

私はこのような配列を持っています:

[{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"},...]

配列全体を反復処理せずに、条件に一致するオブジェクトのインデックスを取得するにはどうすればよいですか?

たとえば、与えられたprop2=="yutu"、私はインデックスを取得したいと思います1

私は見ました.indexOf()が、のような単純な配列に使用されていると思います["a1","a2",...]。私もチェックしました$.grep()が、これはインデックスではなくオブジェクトを返します。

回答:


733

2016年の時点では、Array.findIndex(ES2015 / ES6標準)を使用することになっています。

a = [
  {prop1:"abc",prop2:"qwe"},
  {prop1:"bnmb",prop2:"yutu"},
  {prop1:"zxvz",prop2:"qwrq"}];
    
index = a.findIndex(x => x.prop2 ==="yutu");

console.log(index);

Google Chrome、Firefox、Edgeでサポートされています。Internet Explorerの場合、リンクされたページにポリフィルがあります。

パフォーマンスノート

関数呼び出しはコストがかかるため、本当に大きな配列を使用すると、単純なループのパフォーマンスが次のように向上しますfindIndex

let test = [];

for (let i = 0; i < 1e6; i++)
    test.push({prop: i});


let search = test.length - 1;
let count = 100;

console.time('findIndex/predefined function');
    let fn = obj => obj.prop === search;

    for (let i = 0; i < count; i++)
        test.findIndex(fn);
console.timeEnd('findIndex/predefined function');


console.time('findIndex/dynamic function');
    for (let i = 0; i < count; i++)
        test.findIndex(obj => obj.prop === search);
console.timeEnd('findIndex/dynamic function');


console.time('loop');
    for (let i = 0; i < count; i++) {
        for (let index = 0; index < test.length; index++) {
            if (test[index].prop === search) {
                break;
            }
        }
    }
console.timeEnd('loop');

ほとんどの最適化と同様に、これは慎重に、実際に必要な場合にのみ適用する必要があります。


3
ここには一時的な配列の必要性はありません。イテレータ関数がコンテキストを閉じて変数を使用するという事実を使用するだけです。また、jQuery以外のバージョンは機能しません(それがインデックスにあるとし0たら?)どちらのソリューションは、配列が(それのオッズはとても大きく、Aの人間であるが、ルックアップが起こっている場合を除き、低い気付くだろう大きければ少ない理想的である必要以上の繰り返し、やるたくさん)。
TJクラウダー2013

@ thg435:それでも、単純なレバーでうまくいくRube Goldbergマシンのビットだと思ってください。:-)でもねえ、それはうまくいきます!
TJクラウダー2013

4
x => x.prop2=="yutu"findIndex()でどのように機能するか説明していただけますか?
Abhay Pai

5
@AbhayPai:同じですfunction(x) { return x.prop2=="yutu" }
georg

6
私はポリフィルを使うという提案が好きです。ただし、記述されたコードは、arrow / lambda関数を使用しているため、ポリフィルを使用してもIE11では失敗します。index = a.findIndex(function (x) { return x.prop2 == "yutu" })ポリフィルコードを使用してfindIndexがIE11で機能するように問題を修正して書き直されました
Rick Glos

26

条件に一致するオブジェクトのインデックスを取得するにはどうすればよいですか?

できません。何かが配列を反復処理する必要があります(少なくとも1回)。

条件が大きく変化する場合は、ループしてオブジェクトを調べ、条件に一致するかどうかを確認する必要があります。ただし、ES5機能を備えたシステムでは(またはシムをインストールした場合)、その反復はかなり簡潔に行うことができます。

var index;
yourArray.some(function(entry, i) {
    if (entry.prop2 == "yutu") {
        index = i;
        return true;
    }
});

これはnew(ish)Array#some関数を使用します。これは、指定した関数がtrueを返すまで配列のエントリをループします。私が与えた関数は、一致するエントリのインデックスを保存してtrueから、反復を停止するために戻ります。

または、もちろん、forループを使用します。さまざまな反復オプションについては、この別の回答で説明しています。

ただし、このルックアップで常に同じプロパティを使用する場合、およびプロパティ値が一意である場合は、1回だけループしてオブジェクトを作成し、それらをマッピングできます。

var prop2map = {};
yourArray.forEach(function(entry) {
    prop2map[entry.prop2] = entry;
});

(または、繰り返しになりますが、forループまたはその他のオプションをます)。

次に、でエントリを検索する必要がある場合はprop2 = "yutu"、これを行うことができます。

var entry = prop2map["yutu"];

これを「クロスインデックス」と呼びます。当然、エントリを削除または追加する(またはそのprop2値を変更する)場合は、マッピングオブジェクトも更新する必要があります。


説明ありがとう!jQueryが指し示すソリューションthg435は、私が望んでいたことを実行しました...
アンプ

21

TJ Crowderが言ったことは、とにかくある種の隠された反復があるでしょう。

var index = _.findIndex(array, {prop2: 'yutu'})

1
さまざまな方法でループしてインデックスを取得できますが、ネイティブアレイメソッドにES6で採用されていても、インデックスが最良のソリューションです
Kelly Milligan

13
var CarId = 23;

//x.VehicleId property to match in the object array
var carIndex = CarsList.map(function (x) { return x.VehicleId; }).indexOf(CarId);

そして、基本的な配列番号の場合、これを行うこともできます:

var numberList = [100,200,300,400,500];
var index = numberList.indexOf(200); // 1

配列に値が見つからない場合は-1が返されます。


11
var index;
yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' ? (index = i, true) : false;
});

配列のすべての要素を反復処理します。インデックスが返され、条件が一致しない場合はtrueまたはfalseが返されます。

重要なのは、trueの明示的な戻り値(またはブール結果がtrueである値)です。0のインデックス(Boolean(0)=== false)がある可能性があるため、単一の割り当てでは不十分です。これはエラーにはなりませんが、反復の中断を無効にします。

編集する

上記のさらに短いバージョン:

yourArray.some(function (elem, i) {
    return elem.prop2 === 'yutu' && ~(index = i);
});

2番目のスニペットで〜キャラクターは何をしますか?
serkan

@serkan、これはビット単位のNOT|演算子であり、インデックスが存在する場合、それはインデックス(-1を使用)から / 偽の結果を取得する短いバージョンです。
Nina Scholz、2018年

ありがとう、ニーナ、〜文字がなければ、コードはそのまま機能しますよね?
セルカン2018年

@serkan、あなたの質問は明確ではありませんが、それなし~ではそのように機能しません。
Nina Scholz、2018年

1
ああ、!!(index = 0)!!~(index = 0)確かに違い。ありがとう!
セルカン2018年

4

Array.prototype.some()を次のように使用できます他の回答で述べたとおり)。

https://jsfiddle.net/h1d69exj/2/

function findIndexInData(data, property, value) {
    var result = -1;
    data.some(function (item, i) {
        if (item[property] === value) {
            result = i;
            return true;
        }
    });
    return result;
}
var data = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]



alert(findIndexInData(data, 'prop2', "yutu")); // shows index of 1

4

上記で多くの解決策を見てきました。

ここでは、map関数を使用して、配列オブジェクト内の検索テキストのインデックスを検索しています。

生徒のデータを使用して私の答えを説明します。

  • ステップ1:生徒用の配列オブジェクトを作成します(オプションで独自の配列オブジェクトを作成できます)。
    var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

  • ステップ2:テキストを検索する変数を作成する
    var studentNameToSearch = "Divya";

  • ステップ3:一致したインデックスを格納する変数を作成します(ここではmap関数を使用して反復しています)。
    var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

var students = [{name:"Rambabu",htno:"1245"},{name:"Divya",htno:"1246"},{name:"poojitha",htno:"1247"},{name:"magitha",htno:"1248"}];

var studentNameToSearch = "Divya";

var matchedIndex = students.map(function (obj) { return obj.name; }).indexOf(studentNameToSearch);

console.log(matchedIndex);

alert("Your search name index in array is:"+matchedIndex)


3
function findIndexByKeyValue(_array, key, value) {
    for (var i = 0; i < _array.length; i++) { 
        if (_array[i][key] == value) {
            return i;
        }
    }
    return -1;
}
var a = [
    {prop1:"abc",prop2:"qwe"},
    {prop1:"bnmb",prop2:"yutu"},
    {prop1:"zxvz",prop2:"qwrq"}];
var index = findIndexByKeyValue(a, 'prop2', 'yutu');
console.log(index);

1

正確に反復したくないのはなぜですか?新しいArray.prototype.forEachは、この目的に最適です。

必要に応じて、バイナリ検索ツリーを使用して、単一のメソッド呼び出しで検索できます。これは、JSのBTreeと赤黒の検索ツリー(https://github.com/vadimg/js_bintrees)の適切な実装ですが、インデックスを同時に見つけることができるかどうかはわかりません。


1

Array.reduce()を使用した1つのステップ-jQueryなし

var items = [{id: 331}, {id: 220}, {id: 872}];

var searchIndexForId = 220;
var index = items.reduce(function(searchIndex, item, index){
  if(item.id === searchIndexForId) { 
    console.log('found!');
    searchIndex = index;
  }
  return searchIndex;
}, null);

nullインデックスが見つからなかった場合に戻ります。


0
var list =  [
                {prop1:"abc",prop2:"qwe"},
                {prop1:"bnmb",prop2:"yutu"},
                {prop1:"zxvz",prop2:"qwrq"}
            ];

var findProp = p => {
    var index = -1;
    $.each(list, (i, o) => {
        if(o.prop2 == p) {
            index = i;
            return false; // break
        }
    });
    return index; // -1 == not found, else == index
}

0

GeorgはES6がこのためにArray.findIndexを持っていると既に述べています。そして、他のいくつかの答えは、Array.someメソッドを使用したES5の回避策です。

もう1つのエレガントなアプローチは

var index;
for(index = yourArray.length; index-- > 0 && yourArray[index].prop2 !== "yutu";);

同時に、強調しておきますが、Array.someは、バイナリまたはその他の効率的な検索技術を使用して実装できます。そのため、一部のブラウザーではforループよりもパフォーマンスが向上する可能性があります。


0

このコードを試してください

var x = [{prop1:"abc",prop2:"qwe"},{prop1:"bnmb",prop2:"yutu"},{prop1:"zxvz",prop2:"qwrq"}]
let index = x.findIndex(x => x.prop1 === 'zxvz')
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.