オブジェクトの配列で、属性が検索に一致するオブジェクトのインデックスを見つける最も速い方法


135

私はこれを行うための効率的な方法を見つけるために少しサーフィンをしてきましたが、どこにも行きませんでした。次のようなオブジェクトの配列があります。

array[i].id = some number;
array[i].name = some name;

私がやりたいのは、idが0、1、2、3、4のいずれかに等しいオブジェクトのINDEXESを見つけることです。たとえば、次のようにすることができます。

var indexes = [];
for(i=0; i<array.length; i++) {
  (array[i].id === 0) ? { indexes[0] = i }
  (array[i].id === 1) ? { indexes[1] = i }
  (array[i].id === 2) ? { indexes[2] = i }
  (array[i].id === 3) ? { indexes[3] = i }
  (array[i].id === 4) ? { indexes[4] = i }
}

これは機能しますが、特にarray.lengthが大きくなる可能性がある場合は、非常に高価で遅くなります(醜いことは言うまでもありません)。これを少し改善するためのアイデアはありますか?どういうわけかarray.indexOfを使用することを考えましたが、構文を強制する方法がわかりません。この

array.indexOf(this.id === 0);

たとえば、おそらく必要に応じて、undefinedを返します。前もって感謝します!


1
単純な古い配列がある場合、実行できることは反復のみです。それが配列とは何か、配列のインデックスで並べられたオブジェクトの束です。
デイブニュートン

2
今日この投稿に出くわすと、すべての後発者のためArray.prototype.findIndex()にECMAScript 2015に新しい配列メソッドがあります。受け入れられた答えは素晴らしいものでした。
Conrad Lo

私はES6構文のファンです(レガシーブラウザでのサポートが必要な場合は、ポリフィルを使用してください)。ES7 + ES8は将来の予定です
Fr0zenFyr

回答:


391

「マップ」などの高次関数を使用したいと思うかもしれません。「フィールド」属性で検索したい場合:

var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);
var objectFound = array[elementPos];

9
この回答はすばらしいです。インデックスを提供することで実際に質問に答えるためです:)
対抗

3
@ZeroAbsolute適用された関数(マップに渡されます)は、基準で指定された可能な組み合わせごとに一意のキーを提供する必要があるハッシュ文字列を返すことができます。例:function hashf(el) { return String(el.id) + "_" + String(el.name); }。これは単なるヒントです。elementPos = array.map(hashf(x)).indexOf(hash({id:3, name:'Pablo'}));明らかに、私が提供するハッシュ関数'_'は、値の一部を形成する可能性があるため、すべての場合に有効なわけではありませんが、さまざまなハッシュ方法を理解できる簡単な例にすぎません。
パブロフランシスコペレスイダルゴ2014

1
見つからない場合、これは何を返しますか?私は-1を想定しています。実験します。
Nathan C. Tresch 2015

1
@ NathanC.Tresch indexOf与えられた値が見つからない場合の戻り値であるため、-1を返します。
パブロフランシスコペレスイダルゴ

2
皆さん、こんにちは。2つの方法map, indexOfを使用する代わりに、1つのfindIndex....... と呼ばれる方法を使用できます。例:[{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3}) OR [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)
Umair Ahmed

64

配列内の要素インデックスを見つける最も簡単で簡単な方法。

ES5の構文: [{id:1},{id:2},{id:3},{id:4}].findIndex(function(obj){return obj.id == 3})

ES6の構文: [{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)


4
これが最もエレガントなソリューションだと思います。下位互換性が心配な方はfindIndexdeveloper.mozilla.org
en

2
ES6 lintツールで、obj.id == 3ここで使用されている演算子が予期しない型変換を引き起こす可能性があるという警告が表示されるので、obj.id === 3代わりに演算子を使用して、値と型が等しいかどうかをテストします。
スクラーク

1
この回答は、上記の承認された回答より少なくとも3.5倍高速です。使用var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor);に0.03500000002532033ミリ秒かかりました使用[{id:1},{id:2},{id:3},{id:4}].findIndex(obj => obj.id == 3)に0.00999999747378752ミリ秒かかりました。
Ovidio Reyna

1
この回答は、配列全体を反復処理しないため、最も効率的です。選択された回答は完全な配列をマップし、次に配列全体を1回反復するためにバインドされているfindIndex
Karun

26

新しいArrayメソッド.filter()はこれに適しています。

var filteredArray = array.filter(function (element) { 
    return element.id === 0;
});

jQueryは.grep()でもこれを行うことができます

編集:これらの関数は両方とも内部で繰り返されるだけであり、これらの関数と独自のフィルター関数のローリングとの間に顕著なパフォーマンスの違いはありませんが、ホイールを再発明する理由について言及する価値があります。


+1、私はいつもオブジェクトに対するこのような組み込み関数を忘れています。
Tejs

59
これはインデックスを返しません。
アダムグラント

これはこの特定の質問には答えませんが、私をたくさん助けてくれます!ありがとう!
rochasdv 2015年

これはインデックスを返しません。
リッチ

10

パフォーマンスを重視する場合は、検索フィルターマップ、または上記の方法のいずれかを使用しないでください。

これが最速の方法を示す例です。ここは実際のテストへのリンクです

セットアップブロック

var items = []

for(var i = 0; i < 1000; i++) {
    items.push({id: i + 1})
}

var find = 523

最速の方法

var index = -1
for(var i = 0; i < items.length; i++) {
    if(items[i].id === find) {
        index = i;
        break;
    }
}

遅い方法

items.findIndex(item => item.id === find)

SLOWESTメソッド

items.map(item => item.id).indexOf(find);

2
この比較を提供してくれてありがとう!非常に興味深いのは、パフォーマンスがどれだけ変化するかです。たとえば、実行に使用したブラウザー/ JavaScriptエンジンに応じて、どちらの方法がより速く変化するかなどです。
Iain Collins

1
これは答えとしてマークされるべきだと思います。これは最速の方法と遅い方法を示しています。
鎮痛剤

ベンチマークでは、ブロック2(findIndexを使用)の方が実際には高速です(Microsoft Edge Chromium 83.0.474.0)
rezadru

ブロック2がクロームでも高速になりました
cody mikol

8
array.forEach(function (elem, i) {  // iterate over all elements of array
    indexes[elem.id] = i;           // take the found id as index for the
});                                 // indexes array and assign i

結果はIDのルックアップリストです。指定されたIDで、レコードのインデックスを取得します。


6
var indices = [];
var IDs = [0, 1, 2, 3, 4];

for(var i = 0, len = array.length; i < len; i++) {
    for(var j = 0; j < IDs.length; j++) {
        if(array[i].id == ID) indices.push(i);
    }
}

6

通常の配列を使用して答えがないのでfind

var one = {id: 1, name: 'one'};
var two = {id: 2, name:'two'}
var arr = [one, two] 

var found = arr.find((a) => a.id === 2)

found === two // true

arr.indexOf(found) // 1

3

ES6を使用する新しい方法

let picked_element = array.filter(element => element.id === 0);

picked_elementこの場合は配列です...
異端の猿

3

const index = array.findIndex(item => item.id === 'your-id');

これにより、ID === your-idの配列内のアイテムのインデックスが取得されます。

array = [ {id:1}, {id:2} ];

const index = array.findIndex(item => item.id === 2);

console.log(index);


2

テスト用のコールバックを持つ単純なイテレーターを作成できるように思えます。そのようです:

function findElements(array, predicate)
{
    var matchingIndices = [];

    for(var j = 0; j < array.length; j++)
    {
        if(predicate(array[j]))
           matchingIndices.push(j);
    }

    return matchingIndices;
}

次に、次のように呼び出すことができます:

var someArray = [
     { id: 1, text: "Hello" },
     { id: 2, text: "World" },
     { id: 3, text: "Sup" },
     { id: 4, text: "Dawg" }
  ];

var matchingIndices = findElements(someArray, function(item)
   {
        return item.id % 2 == 0;
   });

// Should have an array of [1, 3] as the indexes that matched

2

Tejsの答えをmongoDBとRobomongoに適応させる

matchingIndices.push(j);

matchingIndices.push(NumberInt(j+1));

2

ES6 map関数の使用:

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);

2

上記の素晴らしい答えのすべてと、すべてのインデックスの検索に関する私の答えの追加を要約すると、コメントの一部から発生しました。

  1. 最初の発生のインデックスを返します。

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }];
const idYourAreLookingFor = 2;

//ES5 
//Output: 1
array.map(function (x) { return x.id; }).indexOf(idYourAreLookingFor);

//ES6 
//Output: 1
array.findIndex(obj => obj.id === idYourAreLookingFor);

  1. すべての出現のインデックス配列を返すには、reduceを使用します。

const array = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 2 }]
const idYourAreLookingFor = 2;

//ES5
//Output: [1, 4]
array.reduce(function (acc, obj, i) {
  if (obj.id === idYourAreLookingFor)
    acc.push(i);
  return acc;
}, []);

//ES6
//Output: [1, 4]
array.reduce((acc, obj, i) => (obj.id === idYourAreLookingFor) ? acc.concat(i) : acc, [])


0

まだコメントはできませんが、Umair Ahmedが投稿した方法に基づいて使用したソリューションを示したいと思いますが、値ではなくキーを検索したい場合は、次のようにします。

[{"a":true}, {"f":true}, {"g":false}]
.findIndex(function(element){return Object.keys(element)[0] == "g"});

私はそれが拡張された質問に答えないことを理解していますが、タイトルは各オブジェクトに何が求められているかを指定していません。最速のソリューション。


0

スーパー配列と呼ばれる小さなユーティリティを作成しました。O (1)の複雑さを持つ一意の識別子によって配列内の項目にアクセスできます。例:

const SuperArray = require('super-array');

const myArray = new SuperArray([
  {id: 'ab1', name: 'John'},
  {id: 'ab2', name: 'Peter'},
]);

console.log(myArray.get('ab1')); // {id: 'ab1', name: 'John'}
console.log(myArray.get('ab2')); // {id: 'ab2', name: 'Peter'}

個人的なオープンソースライブラリを提供する方法をお読みくださいこれをどこにでも投稿する前に。
Martijn Pieters

@MartijnPieters私はいくつかの関連する質問にのみ投稿しました、そしてプロジェクトはMITフリーですのでどうですか?多分あなたはもう少し寛容かもしれません。
パトトーマ2017

0
var test = [
  {id:1, test: 1},
  {id:2, test: 2},
  {id:2, test: 2}
];

var result = test.findIndex(findIndex, '2');

console.log(result);

function findIndex(object) {
  return object.id == this;
}

インデックス1を返します(ES 2016でのみ機能します)


0

ネストの深さに関係なく、オブジェクトの任意の値と簡単に比較できるため、この方法が好きです。

 while(i<myArray.length && myArray[i].data.value!==value){
  i++; 
}
// i now hows the index value for the match. 
 console.log("Index ->",i );
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.