JavaScriptのプロパティでオブジェクトのインデックスを取得するにはどうすればよいですか?


241

たとえば、私は:

var Data = [
  { id_list: 1, name: 'Nick', token: '312312' },
  { id_list: 2, name: 'John', token: '123123' },
]

次に、このオブジェクトをたとえばで並べ替え/反転したいとしますname。そして、私はこのようなものを手に入れたいです:

var Data = [
  { id_list: 2, name: 'John', token: '123123' },
  { id_list: 1, name: 'Nick', token: '312312' },
]

そして今私はプロパティを持つオブジェクトのインデックスを知りたいです name='John'はプロパティトークンの値を取得するためにを。

どうすれば問題を解決できますか?


プロパティを検索する前に、なぜリストを最初にソートしたいのですか?
JJJ 2011

JavaScriptオブジェクトは{Key:Value}、あなたのために修正しました。
ロケットハズマット2011


回答をスキャンすると、ネイティブDataオブジェクトがあるように見えます。慣習に反する、大文字の変数名にすぎません。他の誰かがこれに悩まされている場合は、この命名を修正するために質問と回答を編集します。
Roy Prins

回答:


170

他の答えが示唆するように、配列をループするのがおそらく最良の方法です。しかし、私はそれをそれ自体の関数に入れて、もう少し抽象的なものにします:

function findWithAttr(array, attr, value) {
    for(var i = 0; i < array.length; i += 1) {
        if(array[i][attr] === value) {
            return i;
        }
    }
    return -1;
}

var Data = [
    {id_list: 2, name: 'John', token: '123123'},
    {id_list: 1, name: 'Nick', token: '312312'}
];

これにより、「John」を含むものを見つけるだけでなく、トークン「312312」を含むものを見つけることができます。

findWithAttr(Data, 'name', 'John'); // returns 0
findWithAttr(Data, 'token', '312312'); // returns 1
findWithAttr(Data, 'id_list', '10'); // returns -1

編集:Array.prototype.indexOf() と同じ構成に従うように、見つからない場合は-1を返すように関数を更新しました


1
これを拡張して、1つの属性レベルよりも深い検索をカバーするための回答を追加しました。このクリスに感謝-本当に助けられました:D
Ed Shee

3
このソリューションで問題が発生する場合、===等号は値だけでなくデータ型もチェックすることに注意してください。そのため、実際の値が文字列の場合、日付、数値、空の値を比較するとfalseが返されることがあります。データ型が重要でない場合は、==等号を使用できます。
David Addoteye 2016

これを行わないでください。高階関数の使い方を学ぶこれは古いやり方です。
主導

327

ソート部分はすでに答えられているので。配列内のプロパティのindexOfを取得する別のエレガントな方法を提案します

あなたの例は:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},
    {id_list:2,name:'John',token:'123123'}
]

できるよ:

var index = Data.map(function(e) { return e.name; }).indexOf('Nick');

Array.prototype.mapIE7またはIE8では使用できません。ES5の互換性

そして、ここではES6と矢印構文を使用していますが、さらに簡単です。

const index = Data.map(e => e.name).indexOf('Nick');

4
何があっても配列全体を反復処理する必要があります。最初の方法は必要ありません。
ドイツのAttanasio 2014年

1
シンプルですが、大規模なデータセットを使用する場合のパフォーマンスを考慮に入れてください
gavioto 2015年

1
本当に素晴らしい答えがこの問題を助けてくれました!
NiallMitch14 2016年

1
このソリューションは素晴らしいです。千歳になるために生きられますように
deepelement

3
ES6バージョンでマップを実行してからindexOfを実行しても、配列を2回ループすることになります。代わりに、私の回答に示されているfindIndexメソッドを使用する必要があります
silverlight513

209

ES6の使用に問題がない場合。配列にfindIndex関数が追加されました。つまり、次のようなことができます。

const index = Data.findIndex(item => item.name === 'John');

6
最も直接的でエレガントな解決策を手に入れ、findIndexが貪欲であることを小さくします-私の場合はそれは完璧でした-が、ユーザーは重複する値を持つオブジェクト(つまりを持つ2つのオブジェクトname: John)がある場合、これだけが返されることに注意してください最初の試合
GrayedFox 2017年

驚くばかり!!ありがとうございました。
moreirapontocom

@GrayedFox欲張りじゃないってこと?貪欲はより多くの結果を意味し、findIndexは最初の一致のみを返します。
Jos

1
@Josさん、申し訳ありませんが、貪欲な検索アルゴリズムが何をするのよく理解できていません。貪欲なアルゴリズムは、手元にある情報のみを考慮します。これは、たとえば、結果が1つだけ必要な場合にリスト内のアイテムを検索する場合など、計算上効率的です。findIndexメソッドは最初の一致のみを返すため、貪欲です。貪欲でなければ、検索を続けます。あなたは日常の英語で使われている「貪欲」という言葉を考えていますが、プログラミング(つまりSO)の文脈では、それはあなたが考えるものの反対です;)
GrayedFox

@GrayedFoxを説明していただきありがとうございます。私の貪欲への言及は実際にはプログラミングからもですが、貪欲が貪欲でないよりも多くの文字をとる正規表現に関連しています!:-)
Jos

28
var index = Data.findIndex(item => item.name == "John")

これは、以下の簡易バージョンです。

var index = Data.findIndex(function(item){ return item.name == "John"})

mozilla.orgから

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


2
文字列の比較には「===」を使用してください。これは、この回答に欠けている唯一のものです。
Bruno Tavares

@BrunoTavares、この場合、どのシナリオが異なると思いますか?
edank

1
@edank OPがtokenフィールドではなくフィールドをチェックする場合name、にData[0].token == 312312評価されるtrueがにData[0].token === 321321評価されるため、問題が発生する可能性がありますfalse
-kem


23

IEで問題が発生している場合は、9.0以降でサポートされているmap()関数を使用できます。

var index = Data.map(item => item.name).indexOf("Nick");

1
以下の回答は詳細情報を提供し、最初に投稿されました。
Alexander

これは間違いなくこれに対する最良の解決策です。
Bebolicious

4

私が知っている唯一の方法は、すべての配列をループすることです:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name==="John"){index=i;break;}

または大文字と小文字を区別しない:

var index=-1;
for(var i=0;i<Data.length;i++)
  if(Data[i].name.toLowerCase()==="john"){index=i;break;}

結果の変数インデックスには、オブジェクトのインデックスが含まれるか、見つからない場合は-1が含まれます。


2

典型的な方法

(function(){
  if (!Array.prototype.indexOfPropertyValue){
    Array.prototype.indexOfPropertyValue = function(prop,value){
      for (var index = 0; index < this.length; index++){
        if (this[index][prop]){
          if (this[index][prop] == value){
            return index;
          }
        }
      }
      return -1;
    }
  }
 })();
 // usage:
 var Data = [
 {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}];
 Data.indexOfPropertyValue('name','John'); // returns 1 (index of array);
 Data.indexOfPropertyValue('name','Invalid name') // returns -1 (no result);
 var indexOfArray = Data.indexOfPropertyValue('name','John');
 Data[indexOfArray] // returns desired object.

私の状況で機能するようにこれを少し変更する必要がありました。値がnullのプロパティのインデックスを探していて、5行目でこのインデックスがスキップされていました。
David Brunow、2014

1

カスタム関数をパラメーターとして使用してArray.sortを使用すると、並べ替えのメカニズムを定義できます。

あなたの例では、それは与えるでしょう:

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
]

Data.sort(function(a, b){
    return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
});

alert("First name is : " + Data[0].name); // alerts 'John'
alert("Second name is : " + Data[1].name); // alerts 'Nick'

ソート関数は、aがbの前に来る場合は-1、aがbの後に来る場合は1、両方が等しい場合は0を返す必要があります。配列をソートするためにソート関数で適切なロジックを定義するのはあなた次第です。

編集:インデックスを知りたい質問の最後の部分を逃しました。他の人が言ったように、配列をループしてそれを見つける必要があります。


1

配列を調べて、位置を見つけます。

var i = 0;
for(var item in Data) {
    if(Data[item].name == 'John')
        break;
    i++;
}
alert(i);

これはであるはずですif(Data[item].name == 'John')、私はあなたのためにそれを修正しました。
ロケットハズマット2011

これには一瞬があります。「見つからない」変数iには正のインデックスが含まれます。そして、テストに私=== Data.length場合ニーズは比較すること「が見つかりません」
アンドリューD.

2番目の瞬間は、配列に非インデクサーカスタムプロパティが含まれる場合です。例:var Data [1,2,3,4,5]; データ["テスト"] = 7897; 次の出力を比較します。for(var i in Data)alert(Data [i]); および(var i = 0; i <Data.length; i ++)alert(Data [i]);
Andrew D.


1

小さな回避策を使用しないのはなぜですか?

名前をインデックスとして持つ新しい配列を作成します。その後、すべての検索でインデックスが使用されます。つまり、ループは1つだけです。その後、すべての要素をループする必要はありません!

var Data = [
    {id_list:1, name:'Nick',token:'312312'},{id_list:2,name:'John',token:'123123'}
    ]
var searchArr = []
Data.forEach(function(one){
  searchArr[one.name]=one;
})
console.log(searchArr['Nick'])

http://jsbin.com/xibala/1/edit

実例。


これは、最初にすべてをループすることを意味します...次に、オブジェクトを変更します(オブジェクトを複製しない限り、それはさらにオーバーヘッドになります)。その後、再びループします(少なくとも部分的に)。
Jos

1

私の場合、1つの属性レベルよりも深く検索する必要があったため、Chris Pickettの回答を拡張しました。

function findWithAttr(array, attr, value) {
  if (attr.indexOf('.') >= 0) {
    var split = attr.split('.');
    var attr1 = split[0];
    var attr2 = split[1];
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr1][attr2] === value) {
        return i;
      }
    }
  } else {
    for(var i = 0; i < array.length; i += 1) {
      if(array[i][attr] === value) {
        return i;
      }
    }
  };
};

'attr1.attr2'を関数に渡すことができます


1

これはどうですか ?:

Data.indexOf(_.find(Data, function(element) {
  return element.name === 'John';
}));

lodashまたはunderscorejsを使用していると仮定します。


1
var fields = {
teste:
{
    Acess:
    {
        Edit: true,
      View: false

      }
 },
teste1:
{
    Acess:
    {
        Edit: false,
      View: false

      }
  }
};

console.log(find(fields,'teste'));
function find(fields,field){
    for(key in fields){
        if(key == field){
        return true;
    }
}
return false;
}

内部に複数のオブジェクトがある1つのオブジェクトがあり、マスターオブジェクトにオブジェクトが含まれているかどうかを知りたい場合は、find(MasterObject、 'Object to Search')と入力するだけです。この関数は、存在するかどうか(TRUEまたはFALSE)応答を返します。 )、私は上のexempleを見ることができ、これで助けを願っています JSFiddle


現在の問題を修正する方法で、この答えのヘルプOPのための答えを持ついくつかの説明を追加
ρяσѕρєяK

@ρяσѕρєяK、あなたの提案をありがとう、私はすでに説明を追加します:)
ペドロモンテイロアランテス

1
let indexOf = -1;
let theProperty = "value"
let searchFor = "something";

theArray.every(function (element, index) {

    if (element[theProperty] === searchFor) {
        indexOf = index;
        return false;
    }
    return true;
});

1
collection.findIndex(item => item.value === 'smth') !== -1

このコードスニペットは問題を解決する可能性がありますが、説明を含めると、投稿の品質を向上させるのに役立ちます。あなたは将来の読者のための質問に答えていることを覚えておいてください、そしてそれらの人々はあなたのコード提案の理由を知らないかもしれません。また、コードと説明の両方の読みやすさが低下するため、コードを説明コメントで混雑させないようにしてください。
さようならStackExchange 2018年

1

プロパティトークンの値を取得したい場合は、これを試すこともできます

    let data=[
      { id_list: 1, name: 'Nick', token: '312312' },
      { id_list: 2, name: 'John', token: '123123' },
    ]

    let resultingToken =  data[_.findKey(data,['name','John'])].token

ここで、_。findKeyはlodashの関数です


0

ドイツのAttanasio Ruizの答えの代わりに、Array.map()の代わりにArray.reduce()を使用して、2番目のループを排除できます。

var Data = [
    { name: 'hypno7oad' }
]
var indexOfTarget = Data.reduce(function (indexOfTarget, element, currentIndex) {
    return (element.name === 'hypno7oad') ? currentIndex : indexOfTarget;
}, -1);

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.