web-dev-qa-db-ja.com

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

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

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が大きくなる可能性がある場合、非常に高価で遅いようです(looksいことは言うまでもありません)。これを少しスプルースする方法についてのアイデアはありますか? array.indexOfを何らかの方法で使用することを考えましたが、構文を強制する方法がわかりません。この

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

たとえば、おそらくそうであるように、未定義を返します。前もって感謝します!

125
Petrov

「マップ」などの高階関数を使用したい場合があります。 「フィールド」属性による検索が必要であると仮定します。

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

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

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)

51
Umair Ahmed

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

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

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

編集:これらの機能は両方ともボンネットの下で繰り返されるだけであり、これらの機能と独自のフィルター機能のロールの間に顕著なパフォーマンスの違いはありませんが、なぜ車輪を再発明するかを言及する価値があります。

25
jbabey
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で、レコードのインデックスを取得します。

7
Nina Scholz
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
5
enapupe

パフォーマンスに関心がある場合は、findまたはfilterまたはmapまたは上記の方法のいずれか

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

セットアップブロック

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)

最も遅い方法

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

ES6を使用した新しい方法

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

上記のすばらしい回答のすべてを要約し、コメントの一部から発生したすべてのインデックスを見つけることに関する私の回答を追加します。

  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, [])
2
trungk18

MongoDBとRobomongoに対するTejsの回答の変更

matchingIndices.Push(j);

matchingIndices.Push(NumberInt(j+1));
2
user2584621

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

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

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
PulpDood

ES6 map関数を使用する:

let idToFind = 3;
let index = someArray.map(obj => obj.id).indexOf(idToFind);
2
JoeTidee
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
eXtreme

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

 while(i<myArray.length && myArray[i].data.value!==value){
  i++; 
}
// i now hows the index value for the match. 
 console.log("Index ->",i );
0
Daniel Lefebvre

まだコメントできないので、Umair Ahmedが投稿した方法に基づいて使用したソリューションを示したいのですが、値の代わりにキーを検索したい場合:

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

拡張された質問には答えないことを理解していますが、タイトルには各オブジェクトに何が望まれていたかが明記されていないので、これを謙虚に共有して将来的に他の人に頭痛を軽減したいと思います。最速のソリューション。

0
Xander N

super-array という小さなユーティリティを作成しました。このユーティリティでは、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'}
0
patotoma