Как определить, содержит ли массив Javascript объект с атрибутом, равным заданному значению?

У меня есть массив как

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"));

Ответ 1

2018: этот ответ с 2011 года, прежде чем браузеры широко поддерживали методы фильтрации массивов и функции стрелок. Посмотрите ответ CAFxX.

Нет никакого "волшебного" способа проверить что-то в массиве без цикла. Даже если вы используете какую-либо функцию, сама функция будет использовать цикл. То, что вы можете сделать, это выйти из цикла, как только вы найдете то, что ищете, чтобы свести к минимуму время вычислений.

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

Ответ 2

Не нужно изобретать рулевое колесо цикл, по крайней мере, явно (с использованием функций со стрелками, только в современных браузерах):

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 */
}

Ответ 3

Никакой цикл не нужен. Три метода, которые приходят на ум:

Array.prototype.some()

Это самый точный ответ на ваш вопрос, т.е. "проверьте, существует ли что-то", что означает результат bool. Это будет верно, если есть какие-либо объекты "Magenic", иначе false:

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

Array.prototype.filter()

Это вернет массив всех объектов "Magenic", даже если есть только один (вернет одноэлементный массив):

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: Нет причины использовать свободное равенство (==) вместо строгого равенства (===) при проверке имени.

Ответ 4

Принятый ответ все еще работает, но теперь у нас есть собственный метод ECMAScript 6 [Array.find][1] для достижения такого же эффекта.

Цитирование MDN:

Метод find() возвращает значение первого элемента в массиве который удовлетворяет предоставленной функции тестирования. В противном случае undefinedвернулся.

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 Существует polyfill для IE по mozilla

Ответ 5

Если вы не хотите реструктурировать его следующим образом:

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

для которого вы можете сделать if(vendors.Magnetic)

Вам понадобится петля

Ответ 6

В соответствии со спецификацией ECMAScript 6 вы можете использовать findIndex.

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

magenicIndex будет содержать либо 0 (который является индексом в массиве), либо -1, если он не был найден.

Ответ 7

Вот как я это сделаю

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

array.some() проверяет, существует ли хотя бы одно значение в массиве, которое соответствует критериям и возвращает логическое значение. Отсюда вы можете пойти:

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

Ответ 8

Вы не можете без особого изучения объекта.

Вероятно, вам нужно немного изменить структуру, например

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

Затем вы можете просто использовать его, как хэш-запрос.

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

Ответ 9

Как ОП задала вопрос, существует ли ключ или нет.

Более элегантное решение, которое будет возвращать логическое значение с помощью функции сокращения ES6, может быть

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

Примечание. Первоначальный параметр Reduce - false и если массив имеет ключ, он вернет true.

Надеюсь, это поможет для лучшей и чистой реализации кода

Ответ 10

Вы должны зацикливаться, нет никакого способа обойти это.

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 будет быстрее, чем прямой, но это, безусловно, более гибко, когда ситуация становится немного сложнее.

Ответ 11

Если вы используете 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);
}

Ответ 12

Вы можете попробовать это для меня.

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 } ]

Ответ 13

Исправьте меня, если я ошибаюсь.. я мог бы использовать метод forEach как это,

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

В настоящее время я привык к этому, из-за этого простота и понятное слово. Спасибо.

Ответ 14

Вы можете использовать lodash. Если библиотека lodash слишком тяжела для вашего приложения, подумайте о том, что ненужная функция не используется.

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

Это всего лишь один из способов сделать это. Другой может быть:

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);

Надеюсь, мой ответ поможет.

Ответ 15

Чтобы сравнить один объект с другим, я объединяю цикл for (используется для циклического перемещения по объектам) и 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);

Альтернативный способ сравнения одного объекта с другим - использовать вложенный цикл for с Object.keys(). Length, чтобы получить количество объектов в массиве. Код ниже:

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');
    }
}

Ответ 16

В качестве альтернативы вы можете:

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

Ответ 17

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})

Ответ 18

Многие ответы здесь хорошие и довольно легкие. Но если ваш массив объектов имеет фиксированный набор значений, вы можете использовать ниже трюк:

Сопоставьте все имя в объекте.

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.");
}

Ответ 19

Мой подход к решению этой проблемы заключается в использовании 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;
}

Вызов /Usage

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

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

Ответ 20

Тестирование для элементов массива:

JS предлагает функции массива, которые позволяют вам достичь этого относительно легко. Они следующие:

  1. Array.prototype.filter: принимает функцию обратного вызова, которая является тестом, затем массив повторяется с обратным вызовом и фильтруется в соответствии с этим обратным вызовом. Новый фильтрованный массив возвращается.
  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');
}

Ответ 21

Я предпочитаю использовать регулярное выражение.

Если ваш код выглядит следующим образом,

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

Я бы порекомендовал

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