オブジェクト配列のindexOfメソッド?


514

オブジェクトを含む配列のインデックスを取得する最良の方法は何ですか?

このシナリオを想像してください:

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

ここで、プロパティであるindexOfオブジェクト(この例では)が必要です。hello'stevie'1

私はJavaScriptの初心者で、単純なメソッドがあるのか​​、それを行うために独自の関数を作成する必要があるのか​​わかりません。


1
あなたは2つのオブジェクトをマージしたいですかhelloqaz
Armin

いいえ、そうではありません。配列内のオブジェクトのリストが必要です。
アントニオラグーナ

うん、いいよ!プロパティが定義されている配列内のオブジェクト全体の位置を知りたいとします。
Armin

10
私はこのSOの答えでこの正確な問題を解決する非常に単純な関数を見つけました:var elementPos = array.map(function(x) {return x.id; }).indexOf(idYourAreLookingFor); var objectFound = array[elementPos]; [link](stackoverflow.com/a/16100446/1937255
Rick

ES6のArray.indexOfは、受け入れられた回答よりも優れています(ES6が適切に機能する場合)-以下の完全な例を参照してください
yar1

回答:


1045

map関数を使用すると、1行で解決できると思います。

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

58
これは正直に受け入れられる答えであるはずです。最近のほとんどのブラウザーはサポートしていますArray.prototype.map()
AlbertEngelB 2013年

10
IE8ではサポートされていませんが、それが問題でない場合は、これが最善の解決策です。
アントニオラグナ

57
ええと... Array.prototype.map()がマップされたアイテムを含むまったく新しい配列を作成することは注目に値しませんか?したがって、要素数が1000の配列がある場合は、最初に要素数が1000の別の配列を作成してから、検索しますか?このメソッドと単純なforループのパフォーマンスを比較することは価値があると思います。特に、リソースが限られているモバイルプラットフォームで実行している場合。
Doug

7
@Dougパフォーマンスに関するあなたの主張は確かに正しいですが、ボトルネックのプロファイリングが行われるまでほぼ定義どおりにIO /ネットワークにバインドされているアプリケーションについて、正しい考えで1行のコードを7行に置き換えますか?
Jared Smith

6
技術的に縮小さJSファイルは、1行でもあり; D
greaterKing

371

Array.prototype.findIndexは、IE(非エッジ)以外のすべてのブラウザでサポートされています。しかし、提供されるポリフィルは素晴らしいです。

var indexOfStevie = myArray.findIndex(i => i.hello === "stevie");

地図での解決は大丈夫です。しかし、すべての検索で配列全体を繰り返し処理しています。これは、一致が見つかると反復を停止するfindIndexの最悪のケースにすぎません


本当に簡潔な方法はありません 開発者がIE8について心配する必要があった場合)が、一般的な解決策は次のとおりです。

var searchTerm = "stevie",
    index = -1;
for(var i = 0, len = myArray.length; i < len; i++) {
    if (myArray[i].hello === searchTerm) {
        index = i;
        break;
    }
}

または関数として:

function arrayObjectIndexOf(myArray, searchTerm, property) {
    for(var i = 0, len = myArray.length; i < len; i++) {
        if (myArray[i][property] === searchTerm) return i;
    }
    return -1;
}
arrayObjectIndexOf(arr, "stevie", "hello"); // 1

いくつかのメモ:

  1. 配列でfor ... inループを使用しない
  2. 「針」を見つけたら、ループから抜けるか、関数から戻るようにしてください。
  3. オブジェクトの等価性に注意してください

例えば、

var a = {obj: 0};
var b = [a];
b.indexOf({obj: 0}); // -1 not found

関数はsearchTermである必要があるため、searchtermの比較が正しくありません:)
Antonio Laguna

複数の
Joe

3
@SteveBennettパフォーマンスが最適化されたバージョンです。配列の長さは一度だけ決定する必要があります(forループの変数が初期化されるとき)。あなたのケースでは、長さは毎回反復ごとにチェックされます。stackoverflow.com/questions/5349425/…stackoverflow.com/questions/8452317/…も参照してください。 ただし、パフォーマンスがそれほど高くない場合は、特に問題はありません。
loother

1
良い答えですが、いくつかのパフォーマンスベンチマーク(jsperf.com/find-index-of-object-in-array-by-contentsを参照)を行い、ここで説明した関数ベースの回答が2番目に高い回答であるようだとわかりました。私の回答で述べたようにより高性能な唯一のものは、関数ではなくプロトタイプに入れられることになります
ユニフォニック2017年

123

ES2015では、これは非常に簡単です。

myArray.map(x => x.hello).indexOf('stevie')

または、おそらくより大きなアレイのパフォーマンスが向上します。

myArray.findIndex(x => x.hello === 'stevie')

2
ES6を使用するための
適切

私の回答で述べたように、これらの方法はどちらもプロトタイプのforループほどパフォーマンスが良くないことに驚きました。findIndexメソッドのブラウザーサポートは少し貧弱ですが、同じことをしているように見えますが、それでもパフォーマンスが低下しますか?ベンチマークについては、私の回答のリンクを参照してください。
ユニフォニック2017年

目前のタスクでパフォーマンスが重要な場合は、知っておくと便利です。それは私の経験では非常にまれですが、ymmvです。
スティーブベネット

24
var idx = myArray.reduce( function( cur, val, index ){

    if( val.hello === "stevie" && cur === -1 ) {
        return index;
    }
    return cur;

}, -1 );

17

私はPabloの答えが好きですが、Array#indexOfとArray#mapがすべてのブラウザーで機能するわけではありません。アンダースコアは、使用可能な場合はネイティブコードを使用しますが、フォールバックもあります。さらに、Pabloの匿名マップメソッドとまったく同じことを行うためのpluckメソッドがあります。

var idx = _.chain(myArray).pluck("hello").indexOf("Stevie").value();

1
Array.prototype.mapは()IE9 +のためsoportedされ、あなたはIE8、7、6のためのポリフィルを使用することができます。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
ヨハンEchavarria

1
ポリフィルを使用できます。。。または、アンダースコアまたはロダッシュを使用することもできます。これらは基本的に、他のたくさんのグッズが接続されたポリフィルです。アンダースコアの反対は何ですか?サイズ?
tandrewnichols 2014年

私は本当にアンダースコアが好きです、あなたの答えも賢いですが、私見パブロの答えは最もきれいです。
Johann Echavarria、2014年

うわー、そのようなチェーンを使用することを考えたことはありません。私はそれが検索を流暢にする方法が本当に好きです。
ディランピアス

chainここでは不必要です。_.pluck(myArray, 'hello').indexOf('stevie')
スティーブベネット

14

またはプロトタイプ:

Array.prototype.indexOfObject = function arrayObjectIndexOf(property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArr.indexOfObject("name", "stevie");

9
とても便利!既存のArray.indexOfメソッドに干渉しないように、私はprototype.indexOfObjectを選択しますが。 Array.prototype.indexOfObject = function(property, value) { for (var i = 0, len = this.length; i < len; i++) { if (this[i][property] === value) return i; } return -1; };
2013年

1
私はそれを自己実行クロージャーでラップし、古いものを事前に保存し、置換関数の最初の行をの行に沿ったものにしますif (typeof property === 'string' || typeof property === 'number' || typeof property === 'boolean') return oldIndexOf(property, value);。これは、これらが不変であるいくつかのタイプであるためです。また、必要に応じて、ネイティブメソッドへのフォールバックを可能にする3番目の引数も取り上げます。
Isiah Meadows

8

簡単な

myArray.indexOf('stevie','hello')

ユースケース:

  /*****NORMAL****/  
[2,4,5].indexOf(4) ;//OUTPUT 1
 /****COMPLEX*****/
 [{slm:2},{slm:4},{slm:5}].indexOf(4,'slm');//OUTPUT 1
 //OR
 [{slm:2},{slm:4},{slm:5}].indexOf(4,function(e,i){
   return e.slm;
});//OUTPUT 1
/***MORE Complex**/
[{slm:{salat:2}},{slm:{salat:4}},{slm:{salat:5}}].indexOf(4,function(e,i){
   return e.slm.salat;
});//OUTPUT 1

API:

    Array.prototype.indexOfOld=Array.prototype.indexOf

    Array.prototype.indexOf=function(e,fn){
      if(!fn){return this.indexOfOld(e)}
      else{ 
       if(typeof fn ==='string'){var att=fn;fn=function(e){return e[att];}}
        return this.map(fn).indexOfOld(e);
      }
    };

6

ここで、さまざまな回答のパフォーマンステストを行いました。誰でも自分で実行できます。

https://jsperf.com/find-index-of-object-in-array-by-contents

Chromeでの最初のテストに基づくと、次の方法(プロトタイプ内で設定されたforループを使用)が最も高速です。

Array.prototype.indexOfObject = function (property, value) {
    for (var i = 0, len = this.length; i < len; i++) {
        if (this[i][property] === value) return i;
    }
    return -1;
}

myArray.indexOfObject("hello", "stevie");

このコードは、Nathan Zaettaの回答を少し変更したバージョンです。

パフォーマンスベンチマークでは、ターゲットを1000オブジェクト配列の中央(インデックス500)と非常に最後(インデックス999)の両方にして、ターゲットを配列の最後のアイテム(つまり、それが見つかる前に、配列内のすべての項目をループしなければならないことに注意してください)それでも最速になります。

このソリューションには、最後の行だけを繰り返す必要があるため、繰り返し実行するのに最も簡潔であるという利点もあります。

myArray.indexOfObject("hello", "stevie");

2
私は自分のテストでフィドルを使用してこの質問への回答を投稿しようとしていましたが、あなたの回答のおかげで、もう必要はありません。私はあなたのテストを確認したいだけです-私は同じ結果を得ましたが、whileループの代わりにループを使用していますfor、そしてperformance.now()。この回答がもっと支持され、以前に見たことがあれば、少し時間を節約できただろう...
Yin Cognyto


5

ただし、他のほとんどの回答は有効です。場合によっては、使用する場所の近くに短い単純な関数を作成するのが最善です。

// indexOf wrapper for the list of objects
function indexOfbyKey(obj_list, key, value) {
    for (index in obj_list) {
        if (obj_list[index][key] === value) return index;
    }
    return -1;
}
// Find the string in the list (default -1)
var test1 = indexOfbyKey(object_list, 'name', 'Stevie');
var test2 = indexOfbyKey(object_list, 'last_name', 'some other name');

それはあなたにとって何が重要かによる。コードの行を節約し、ワンライナーを使用したり、さまざまなエッジケースをカバーする汎用ソリューションをどこかに置いたりするのは非常に賢明かもしれません。しかし、将来の開発者に追加のリバースエンジニアリング作業を任せるよりも、「ここで私はこのようにした」と言う方が良い場合もあります。特にあなたがあなたの質問のように自分を「初心者」と考えるなら。


4
array.filter(function(item, indx, arr){ return(item.hello === 'stevie'); })[0];

心に [0]

のように使用するのが適切reduceですAntonio Lagunaの答え。

簡潔にお詫び申し上げます...


4

オブジェクトが配列内で使用しているものと同じオブジェクトである場合は、文字列の場合と同じ方法でオブジェクトのインデックスを取得できます。

var hello = {
    hello: 'world',
    foo: 'bar'
};
var qaz = {
    hello: 'stevie',
    foo: 'baz'
}

var qazCLONE = { // new object instance and same structure
    hello: 'stevie',
    foo: 'baz'
}

var myArray = [hello,qaz];

myArray.indexOf(qaz) // should return 1
myArray.indexOf(qazCLONE) // should return -1

これは、IndexOfが値と一致するかどうかが不明だったため、私が探していた答えです。これで、IndexOfを使用してオブジェクトを見つけることができ、同じプロパティを持つ他のオブジェクトがあるかどうか心配する必要はありません。
MDave



3

ポジションを見つけることにのみ興味がある場合は、@ Pabloの回答を参照してください。

pos = myArray.map(function(e) { return e.hello; }).indexOf('stevie');

あなたが楽しみにしている場合は、要素見つける(つまり、あなたがこのような何かをやっての考えていた場合にmyArray[pos])、があり、より効率的な1行使用して、それを行う方法はfilter

element = myArray.filter((e) => e.hello === 'stevie')[0];

パフォーマンス結果を見る(〜+ 42%ops / sec):http : //jsbench.github.io/#7fa01f89a5dc5cc3bee79abfde80cdb3


2

この例を参照してください:http : //jsfiddle.net/89C54/

for (i = 0; i < myArray.length; i++) {
    if (myArray[i].hello === 'stevie') {
        alert('position: ' + i);
        return;
    }
}

ゼロから数え始めます。


2

私は以下をチェックするための一般的な関数を作成しました&コードと任意のオブジェクトで動作します

function indexOfExt(list, item) {
    var len = list.length;

    for (var i = 0; i < len; i++) {
        var keys = Object.keys(list[i]);
        var flg = true;
        for (var j = 0; j < keys.length; j++) {
            var value = list[i][keys[j]];
            if (item[keys[j]] !== value) {
                flg = false;
            }
        }
        if (flg == true) {
            return i;
        }
    }
    return -1;
}

var items = [{ "hello": 'world', "foo": 'bar' }];
var selectedItem = { "hello": 'world', "foo": 'bar' };
alert(items.indexOf(selectedItem));
alert(indexOfExt(items, selectedItem));

最初のアラートは-1(一致が見つからなかったことを意味します)を返し、2番目のアラートは0(一致が見つかったことを意味します)を返します。


2

underscore.jsライブラリ_.findIndexから使用

ここに例があります _.findIndex([{a:1},{a: 2,c:10},{a: 3}], {a:2,c:10}) //1


追加のライブラリからメソッドを提案する場合は、それらがどこから来たかを言及する必要があります。
Craicerjack 2015年

@Steve Bennett nice use.of of the library now in lodash
zabusa

2

ES6 findIndexメソッドを使用して、lodashまたは他のライブラリなしで、次のように記述できます。

function deepIndexOf(arr, obj) {
  return arr.findIndex(function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

これはオブジェクトの直接のプロパティを比較しますが、プロパティに再帰しません。

実装がまだ提供しfindIndexていない場合(ほとんどは提供していません)、この検索をサポートするライトポリフィルを追加できます。

function deepIndexOf(arr, obj) {
  function findIndex = Array.prototype.findIndex || function (pred) {
    for (let i = 0; i < this.length; ++i) {
      if (pred.call(this, this[i], i)) {
        return i;
      }
    }

    return -1;
  }

  return findIndex.call(arr, function (cur) {
    return Object.keys(obj).every(function (key) {
      return obj[key] === cur[key];
    });
  });
}

このだましに関する私の答えから)


2

Array.prototype.findIndex()基本的にネイティブで便利な関数を使用できます。

findIndex()メソッドは、配列の要素が指定されたテスト関数を満たす場合、配列のインデックスを返します。それ以外の場合は-1が返されます。

Internet Explorer、Opera、Safariではサポートされていませんが、以下のリンクにあるポリフィルを使用できます。

詳しくは:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex

var hello = {
  hello: 'world',
  foo: 'bar'
};
var qaz = {
  hello: 'stevie',
  foo: 'baz'
}

var myArray = [];
myArray.push(hello, qaz);

var index = myArray.findIndex(function(element, index, array) {
  if (element.hello === 'stevie') {
    return true;
  }
});
alert('stevie is at index: ' + index);


2

@Monika Garg answerフルトールを使用できますfindIndex()サポートされていないブラウザにはポリフィルがあります)。

私は人々がこの回答に反対票を投じたのを見ました、そして私は私の意見ではこれが最もエレガントな方法であるので間違った構文のために彼らがこれをしたことを望みます。

findIndex()メソッドは、配列の要素が指定されたテスト関数を満たす場合、配列のインデックスを返します。それ以外の場合は-1が返されます。

例えば:

var hello = {
  hello: 'world',
  foo: 'bar'
};
var qaz = {
  hello: 'stevie',
  foo: 'baz'
}

var myArray = [];
myArray.push(hello,qaz);

var index = myArray.findIndex(function(element) {
  return element.hello == 'stevie';
});

alert(index);


メソッドはエレガントに見えますが、MDNによるとIEのサポートはありませんか?developer.mozilla.org/en/docs/Web/JavaScript/Reference/...
Jaakko Karhu

ポリフィルを使用してみてください(回答のリンク)。
Mosh Feu 2016年

1

これは、配列内のオブジェクトのインデックスを見つける方法です

    var myArray = [{  hello: 'world',
        foo: 'bar'
    },{
        hello: 'stevie',
        foo: 'baz'
    }];



    for (i = 0; i < myArray.length; i++) {
        if (myArray[i].hello === 'stevie') {
            alert('position: ' + i);
            return;
        }
    }

0

これはカスタムコードなしで動作します

var arr, a, found;
arr = [{x: 1, y: 2}];
a = {x: 1, y: 2};
found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1;
// found === true

注:これは実際のインデックスを提供せず、オブジェクトが現在のデータ構造に存在するかどうかを通知するだけです


1
インデックスを取得できないため、これは無効です
Antonio Laguna

0

あなたは単に使うことができます

const someId = 2;
const array = [{id:1}, {id:2}, {id:3}];
const index = array.reduce((i, item, index) => item.id === someId ? index : i, -1);
alert('someId ' + someId + ' is at index ' + index);

アンダースコアはありません。


0
var hello = {hello: "world",  foo: "bar"};
var qaz = {hello: "stevie", foo: "baz"};
var myArray = [];
myArray.push(hello,qaz);

function indexOfObject( arr, key, value   ) {
    var j = -1;
    var result = arr.some(function(obj, i) { 
        j++;
        return obj[key] == value;
    })

    if (!result) {
        return -1;
    } else {
        return j;
    };
}

alert(indexOfObject(myArray,"hello","world"));

Arrayメソッドを使用します。
user3235365 2017年

-1

これを行うには、独自のプロトタイプを作成できます。

何かのようなもの:

Array.prototype.indexOfObject = function (object) {
    for (var i = 0; i < this.length; i++) {
        if (JSON.stringify(this[i]) === JSON.stringify(object))
            return i;
    }
}

2
悪い習慣、カプセル化速報:developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/...
HMR

これは、再帰的に定義されたオブジェクトでも機能しなくなります。
Joseph Coco

-2

私はfindIndex()メソッドを使用することを好みます:

 var index = myArray.findIndex('hello','stevie');

index インデックス番号が表示されます。


1
回答、スペル、コードのインデント、:)は間違っていますか?
Sachin Verma 2014

1
findIndexは、JavaScript標準の実装にはありません。そのような方法については次の(ecma 6)提案がありますが、その署名はそうではありません。意味を明確にして(おそらくメソッドの名前)、findIndexメソッドの宣言を行うか、使用しているライブラリに名前を付けてください。
セバスチャンF.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.