JavaScript配列に、指定された値と等しい属性を持つオブジェクトが含まれているかどうかを判断する方法


658

私のような配列があります

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

この配列をチェックして、Magenicが存在するかどうかを確認するにはどうすればよいですか?ループしない限り、ループしたくありません。私は潜在的に数千のレコードを扱っています。


更新しました

これは人気の投稿なので、見つけた新しいものを共有したいと思いました。そして、@ CAFxXはすでにこれを共有しているようです!私はこれらをもっとよく読むべきです。私はhttps://benfrain.com/understanding-native-javascript-array-methods/に出くわしました。

vendors.filter(function(vendor){ return vendor.Name === "Magenic" })

そして、とECMAScriptの2015年には、新しい矢印の機能を使用していても簡単です。

vendors.filter(vendor => vendor.Name === "Magenic")

一見ランダムに見えるコメントはご容赦ください。しかし、質問はJSONに関するものですか、それともJavaScript配列に関するものですか。
アレックスターピン

4
@CAFxXソリューションの方が優れています。選択したソリューションを更新すると、すばらしいでしょう。
eMarine

1
同意しました、それ以前にそれを見なかった!
David Lozzi 16

矢印関数を使用すると、これをさらに簡単にすることができます。最新のブラウザはすべてこれをサポートしており、見栄えがよくなっています。
Piotr Kula 2017年

あなたは非常に
便利

回答:


264

2018年の編集:この回答は、ブラウザーが配列のフィルター方法と矢印関数を広くサポートする前の2011年のものです。CAFxXの回答ご覧ください。

ループなしで配列内の何かをチェックする「魔法の」方法はありません。関数を使用しても、関数自体がループを使用します。できることは、計算時間を最小限に抑えるために探しているものが見つかったらすぐにループから抜け出すことです。

var found = false;
for(var i = 0; i < vendors.length; i++) {
    if (vendors[i].Name == 'Magenic') {
        found = true;
        break;
    }
}

4
問題ない。キースのソリューションも非常に実行可能であり、ループからあなたを救うことに留意してください。
アレックスターピン

2
「何か」が入っているかどうかを知る必要がある場合は、フラグは必要ありません。配列のサイズでスキャンインデックスの値を確認できます。これが機能するためには、インデックスvarがforステートメントの前に宣言されている必要があります。
Alex

5
これらのオプションは現在機能しているようです:vendors.forEach、vendors.filter、vendors.reduce
David Lozzi

1
JSON.stringify(vendors).indexOf( 'Magenic')についてはどうですか?== -1
Last Breath

1
@LastBreath 'Magenic'は、オブジェクト内の別の場所にある場合、非常に簡単に誤検知を引き起こす可能性があります
Alex Turpin

948

再発明する必要はありません ホイールループ、少なくとも明示的ではない(矢印関数最新のブラウザのみを使用):

if (vendors.filter(e => e.Name === 'Magenic').length > 0) {
  /* vendors contains the element we're looking for */
}

または、より良い

if (vendors.some(e => e.Name === 'Magenic')) {
  /* vendors contains the element we're looking for */
}

編集:お粗末なブラウザとの互換性が必要な場合、最善の策は次のとおりです:

if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
  /* vendors contains the element we're looking for */
}

4
@Rocketなぜ私の回答を編集したのですか?中括弧のない構文は完全に有効なjavascriptです。
CAFxX 2011年

4
「lambda」構文は、Chrome 16(粗悪なブラウザではありません)ではまだ機能しません。
ロケットHazmat

27
お粗末なことの定義によると思います。この構文はjavascript 1.8の一部です。
CAFxX

7
表現の閉鎖あなたは第1、第2の例では、ここで使用しているが、持っている非標準を、使用しないでください!Mozillaからの警告(そのリンクを参照)。これらはFirefoxでしか機能しませんでしたが、現在は非推奨となっており、アロー関数を優先して削除されます
doppelgreener 2016

2
@ 7hibault はsome、オブジェクトname === "Magenic"が見つかると短絡する可能性があるためです。を使用filterすると、配列の最後まで各項目をチェックし、条件に一致する新しい配列項目を作成してから、length
adiga

93

ループは必要ありません。頭に浮かぶ3つの方法:

Array.prototype.some()

これはあなたの質問に対する最も正確な答えです。つまり、「何かが存在するかどうかを確認してください」という、ブールの結果を意味します。これは、「Magenic」オブジェクトがある場合はtrue、それ以外の場合はfalseです。

let hasMagenicVendor = vendors.some( vendor => vendor['Name'] === 'Magenic' )

Array.prototype.filter()

これは、1つしかない場合でも、すべての「Magenic」オブジェクトの配列を返します(1要素の配列を返します)。

let magenicVendors = vendors.filter( vendor => vendor['Name'] === 'Magenic' )

これをブール値に強制しようとしても、空の配列(「Magenic」オブジェクトがない)は真実であるため、機能しません。だから使うだけmagenicVendors.length条件付きでしてください。

Array.prototype.find()

これは最初の「Magenic」オブジェクトを返します(またはundefined何もない場合):

let magenicVendor = vendors.find( vendor => vendor['Name'] === 'Magenic' );

これは、ブール値の大丈夫に強制されます(オブジェクトはすべて真実でundefinedあり、偽物です)。


注:プロパティ名の奇妙な大文字小文字の区別のため、vendor.Nameではなくvendor ["Name"]を使用しています。

注2:名前をチェックするときに厳密な等価(===)ではなく、緩い等価(==)を使用する理由はありません。


5
フードの下では、これらはすべてループしていることを指摘しておくと便利です。これらはすべて、単にループ処理および実行操作よりも計算が遅いです。
ThePartyTurtle 2017年

その愛をここで共有することもできます:stackoverflow.com/questions/21748670/…私のようなより多くの人々がその古いページに移動して仮定を行わないでしょう。
ThePartyTurtle 2017年

43

受け入れられた回答は引き続き機能しますが[Array.find][1]、同じ効果を実現するECMAScript 6ネイティブメソッドが用意されました。

MDNの引用:

find()メソッドは、指定されたテスト関数を満たす配列の最初の要素の値を返します。それ以外の場合は、未定義が返されます。

var arr = []; 
var item = {
  id: '21',
  step: 'step2',
  label: 'Banana',
  price: '19$'
};

arr.push(item);
/* note : data is the actual object that matched search criteria 
  or undefined if nothing matched */
var data = arr.find( function( ele ) { 
    return ele.id === '21';
} );

if( data ) {
 console.log( 'found' );
 console.log(data); // This is entire object i.e. `item` not boolean
}

私のjsfiddleリンクを参照してくださいmozillaによって提供される IEのポリフィルがあります


2
あなただけの場合は短くなる可能性がありますreturn ele.id == '2'が、優れたES6ソリューションの場合は+1になります。
ライフィッシュ2016

フレッシュな答えが得意:)パフォーマンスが上記の答えよりも優れているかどうか疑問に思っているだけ
Emidomenge

'data'の戻り値(ele.idが '21'などのIDと一致する場合)が配列アイテム自体(この場合はアイテムオブジェクト全体)になることを指摘することが重要だと思います。データ変数の結果が偽の値ではなく「true」または「false」になると予想されていた場合は、非常にがっかりします。
adamgede 2017年

THX!私の仕事は少し違っていました。配列内のオブジェクトのインデックスを取得=> push if <0 || splice(index, 1)ここに私のaが更新されたコードビットである:const index = this.selected.indexOf(this.selected.find(s => s.id == passedObj.id))
レオニードZadorozhnykh

30

これが私のやり方です

const found = vendors.some(item => item.Name === 'Magenic');

array.some()メソッドは、基準に一致する配列に少なくとも1つの値があるかどうかをチェックし、ブール値を返します。ここからは次のようにできます:

if (found) {
// do something
} else {
// do something else
}

22

次のように再構築したい場合を除きます。

vendors = {
    Magenic: {
      Name: 'Magenic',
      ID: 'ABC'
     },
    Microsoft: {
      Name: 'Microsoft',
      ID: 'DEF'
    } and so on... 
};

あなたにできること if(vendors.Magnetic)

あなたはループする必要があります


2
オブジェクト構造を維持して他の場所で使用したい場合
Keith.Abramo

21

ECMAScript 6仕様に従って、を使用できますfindIndex

const magenicIndex = vendors.findIndex(vendor => vendor.Name === 'Magenic');

magenicIndex0(配列内のインデックスである)または-1見つからなかった場合のいずれかを保持します。


条件として使用された場合、0は依然として偽の結果として一致することを人々に知らせるためです。このため、より論理的な真実の評価が得られるほど、find()の方が良いと思います。
dhj 2018

15

OPがキーが存在するかどうかを質問したので

ES6のreduce関数を使用してブール値を返すよりエレガントなソリューションは、

const magenicVendorExists =  vendors.reduce((accumulator, vendor) => (accumulator||vendor.Name === "Magenic"), false);

注: reduceの初期パラメーターはaでfalseあり、配列にキーがある場合はtrueを返します。

それがより良い、よりクリーンなコード実装に役立つことを願っています


1
!! []がfalseになるのはいつからですか。
セルゲイ、

1
ナイスキャッチ。reduceを使用して回答を更新しました:)
Jay Chakra

1
これは間違っています。の最初のパラメータreduceは、vendorオブジェクトではなくアキュムレータです。これfalse.Name === "Magenic"はすべてのループをチェックインし、falseを返します
adiga

@adiga:修正されました。
ジェイチャクラ

1
Mirza Lekaのソリューションも確認してください。よりエレガントなソリューション。
ジェイチャクラ

13

オブジェクトを実際に調べることなくしてはならない。

おそらく、次のように構造を少し変更する必要があります

vendors = {
    Magenic:   'ABC',
    Microsoft: 'DEF'
};

その後、ルックアップハッシュのように使用できます。

vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined

6

手遅れかもしれませんが、javascript配列には2つのメソッドsomeeveryブール値を返すメソッドがあり、これを実現するのに役立ちます。

someあなたが達成しようとしていることには最も適切だと思います。

vendors.some( vendor => vendor['Name'] !== 'Magenic' )

配列内のオブジェクトのいずれかが指定された条件を満たすことを検証するものもあります。

vendors.every( vendor => vendor['Name'] !== 'Magenic' )

Everyは、配列内のすべてのオブジェクトが指定された条件を満たすことを検証します。


これは機能せず、const array1 = [{name:'Mike'},{name:'Alice'}]; console.log(array1.every(item => item.name !== 'Mike'));trueを返すはずです
Thanwa Ch。

申し訳ありませんsomeが、私の答えを更新します。
Akinjiola Toni

5

あなたはループする必要があります、それを回避する方法はありません。

function seekVendor(vendors, name) {
  for (var i=0, l=vendors.length; i<l; i++) {
    if (typeof vendors[i] == "object" && vendors[i].Name === name) {
      return vendors[i];
    }
  }
}

もちろん、linq.jsのようなライブラリを使用して、これをより楽しいものにすることができます。

Enumerable.From(vendors).Where("$.Name == 'Magenic'").First();

(デモについては、jsFiddleを参照してください)

linq.jsが単純なループよりも高速であるとは思えませんが、少し複雑になると、より柔軟になります。


5

配列要素のテスト:

JSは、これを比較的簡単に実現できる配列関数を提供しています。それらは次のとおりです。

  1. Array.prototype.filter:テストであるコールバック関数を受け取り、配列はisコールバックで反復され、このコールバックに従ってフィルタリングされます。新しいフィルターされた配列が返されます。
  2. Array.prototype.some:テストであるコールバック関数を受け取り、次に配列がコールバックで反復され、いずれかの要素がテストに合格すると 、ブール値trueが返されます。それ以外の場合はfalseが返されます

詳細は例を介して最もよく説明されています:

例:

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } //and so on goes array... 
];

// filter returns a new array, we instantly check if the length 
// is longer than zero of this newly created array
if (vendors.filter(company => company.Name === 'Magenic').length ) {
  console.log('I contain Magenic');
}

// some would be a better option then filter since it directly returns a boolean
if (vendors.some(company => company.Name === 'Magenic')) {
  console.log('I also contain Magenic');
}

ブラウザのサポート:

これら2つの機能はES6機能であり、すべてのブラウザーがそれらをサポートしているとは限りません。これを克服するには、ポリフィルを使用できます。Array.prototype.some(MDNからの)のポリフィルは次のとおりです。

if (!Array.prototype.some) {
  Array.prototype.some = function(fun, thisArg) {
    'use strict';

    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }

    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    for (var i = 0; i < len; i++) {
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }

    return false;
  };
}


4

jqueryを使用している場合は、grepを利用して、一致するすべてのオブジェクトを含む配列を作成できます。

var results = $.grep(vendors, function (e) {
    return e.Name == "Magenic";
});

結果配列を使用します。

for (var i=0, l=results.length; i<l; i++) {
    console.log(results[i].ID);
}

3

私が間違っている場合は修正してください。forEachこのような方法を使用できたかもしれませんが、

var found=false;
vendors.forEach(function(item){
   if(item.name === "name"){
       found=true;

   }
});

今日、私はそれに慣れています。なぜなら、それが単純で自己説明的な言葉だからです。ありがとうございました。


1
注:ここではリターンを使用しない
Edison

2

あなたはこれを私のために試すことができます。

const _ = require('lodash');

var arr = [
  {
    name: 'Jack',
    id: 1
  },
  {
    name: 'Gabriel',
    id: 2
  },
  {
    name: 'John',
    id: 3
  }
]

function findValue(arr,value) {
  return _.filter(arr, function (object) {
    return object['name'].toLowerCase().indexOf(value.toLowerCase()) >= 0;
  });
}

console.log(findValue(arr,'jack'))
//[ { name: 'Jack', id: 1 } ]

さて、これは本当に古い質問であり、私はそのアップデートがすでに今日の最良の解決策を持っていると思います。
フェデリコガルフィオーネ

1

lodashを使用できます。lodashライブラリがアプリケーションにとって重すぎる場合は、使用されていない不要な関数をチャンクすることを検討してください。

let newArray = filter(_this.props.ArrayOne, function(item) {
                    return find(_this.props.ArrayTwo, {"speciesId": item.speciesId});
                });

これは、これを行う1つの方法にすぎません。別のものは次のとおりです。

var newArray=  [];
     _.filter(ArrayOne, function(item) {
                        return AllSpecies.forEach(function(cItem){
                            if (cItem.speciesId == item.speciesId){
                            newArray.push(item);
                          }
                        }) 
                    });

console.log(arr);

上記の例は、次のようなライブラリを使用せず書き換えることもできます。

var newArray=  [];
ArrayOne.filter(function(item) {
                return ArrayTwo.forEach(function(cItem){
                    if (cItem.speciesId == item.speciesId){
                    newArray.push(item);
                  }
                }) 
            });
console.log(arr);

私の答えが役に立てば幸いです。


1

ここでの多くの答えは良く、かなり簡単です。ただし、オブジェクトの配列に固定された値のセットがある場合は、以下のトリックを使用できます。

オブジェクト内のすべての名前をマップします。

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    }
];

var dirtyObj = {}
for(var count=0;count<vendors.length;count++){
   dirtyObj[vendors[count].Name] = true //or assign which gives you true.
}

これで、このdirtyObjをループなしで何度でも使用できます。

if(dirtyObj[vendor.Name]){
  console.log("Hey! I am available.");
}

1

あるオブジェクトを別のオブジェクトと比較するために、for inループ(オブジェクトのループに使用される)とsome()を組み合わせます。配列が範囲外になることを心配する必要がないため、コードを節約できます。.someのドキュメントはここにあります

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var  objectsFound = [];

for(let objectNumber in productList){
    var currentId = productList[objectNumber].id;   
    if (theDatabaseList.some(obj => obj.id === currentId)) {
        // Do what you need to do with the matching value here
        objectsFound.push(currentId);
    }
}
console.log(objectsFound);

あるオブジェクトを別のオブジェクトと比較する別の方法は、Object.keys()。lengthでネストされたforループを使用して、配列内のオブジェクトの量を取得することです。以下のコード:

var productList = [{id: 'text3'}, {id: 'text2'}, {id: 'text4', product: 'Shampoo'}]; // Example of selected products
var theDatabaseList = [{id: 'text1'}, {id: 'text2'},{id: 'text3'},{id:'text4', product: 'shampoo'}];    
var objectsFound = [];

for(var i = 0; i < Object.keys(productList).length; i++){
        for(var j = 0; j < Object.keys(theDatabaseList).length; j++){
        if(productList[i].id === theDatabaseList[j].id){
            objectsFound.push(productList[i].id);
        }       
    }
}
console.log(objectsFound);

正確な質問に答えるには、オブジェクトの値を検索するだけの場合、単一のforループを使用できます。

var vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    } 
];

for(var ojectNumbers in vendors){
    if(vendors[ojectNumbers].Name === 'Magenic'){
        console.log('object contains Magenic');
    }
}

0

または、次のようにすることもできます。

const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));

1
なぜ彼がそれを行うことができるのかを述べたほうがいい
Azzabi Haythem

0

var without2 = (arr, args) => arr.filter(v => v.id !== args.id); 例:

without2([{id:1},{id:1},{id:2}],{id:2})

結果:without2([{id:1}、{id:1}、{id:2}]、{id:2})


結果を言うつもりだったと思います:[{id:1}、{id:1}]
Isaac Pak

0
const a = [{one:2},{two:2},{two:4}]
const b = a.filter(val => "two" in val).length;
if (b) {
   ...
}

3
いくつかの説明を入力し、提供する例が機能することを確認してください(フィルターは元の配列を変更せず、複製します)。
Moshe Simantov

-1

この問題を解決するための私のアプローチは、ES6を使用して、チェックを実行する関数を作成することです。この関数の利点は、プロジェクト全体で再利用可能でkeyあり、指定されたとで指定されたオブジェクトの配列をチェックできることvalueです。

十分な話、コードを見てみましょう

アレイ

const ceos = [
  {
    name: "Jeff Bezos",
    company: "Amazon"
  }, 
  {
    name: "Mark Zuckerberg",
    company: "Facebook"
  }, 
  {
    name: "Tim Cook",
    company: "Apple"
  }
];

関数

const arrayIncludesInObj = (arr, key, valueToCheck) => {
  let found = false;

  arr.some(value => {
    if (value[key] === valueToCheck) {
      found = true;
      return true; // this will break the loop once found
    }
  });

  return found;
}

電話/使用

const found = arrayIncludesInObj(ceos, "name", "Tim Cook"); // true

const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false

-4

私はむしろ正規表現で行きたいです。

あなたのコードが次のようであれば、

vendors = [
    {
      Name: 'Magenic',
      ID: 'ABC'
     },
    {
      Name: 'Microsoft',
      ID: 'DEF'
    }
];

私がお勧めします

/"Name":"Magenic"/.test(JSON.stringify(vendors))

24
一部の人々は、問題に直面したときに、「わかっている、私は正規表現を使用する」と考えます。今、彼らは2つの問題を抱えています。
Craicerjack

あなたが何かをすることができるからといって、これを下に提出してください。
リアム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.