Jak ustalić, czy tablica JavaScript zawiera obiekt z atrybutem równym danej wartości?

658

Mam tablicę jak

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

Jak sprawdzić tę tablicę, aby sprawdzić, czy Magenic istnieje? Nie chcę zapętlać, chyba że muszę. Pracuję z potencjalnie kilkoma tysiącami płyt.


AKTUALIZACJA

Ponieważ jest to popularny post, pomyślałem, że podzielę się czymś nowym, co znalazłem. I wygląda na to, że @CAFxX już to udostępnił! Powinienem je częściej czytać. Natknąłem się na https://benfrain.com/understanding-native-javascript-array-methods/ .

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

A dzięki ECMAScript 2015 korzystanie z nowych funkcji strzałek jest jeszcze prostsze:

vendors.filter(vendor => vendor.Name === "Magenic")
David Lozzi
źródło
Proszę wybaczyć pozornie przypadkowy komentarz, ale czy twoje pytanie dotyczyło JSON, czy tylko tablic JavaScript?
Alex Turpin
4
Rozwiązanie @CAFxX jest lepsze, byłoby niesamowite, jeśli zaktualizujesz wybrane rozwiązanie.
eMarine,
1
Zgadzam się, nie widziałem tego wcześniej!
David Lozzi,
Możesz to jeszcze bardziej uprościć, używając funkcji strzałek. Wszystkie nowoczesne przeglądarki obsługują to i wyglądają ładniej.
Piotr Kula
możesz użyć funkcji mapy, bardzo przydatnej
Monir alhussini,

Odpowiedzi:

264

Edycja 2018 : Ta odpowiedź pochodzi z 2011 roku, zanim przeglądarki szeroko wspierały metody filtrowania tablic i funkcje strzałek. Spojrzeć na odpowiedź CAFxX użytkownika .

Nie ma „magicznego” sposobu sprawdzenia czegoś w tablicy bez pętli. Nawet jeśli użyjesz jakiejś funkcji, sama funkcja użyje pętli. To, co możesz zrobić, to wyjść z pętli, gdy tylko znajdziesz to, czego szukasz, aby zminimalizować czas obliczeniowy.

var found = false;
for(var i = 0; i < vendors.length; i++) {
    if (vendors[i].Name == 'Magenic') {
        found = true;
        break;
    }
}
Alex Turpin
źródło
4
Nie ma problemu. Pamiętaj, że rozwiązanie Keitha jest również bardzo opłacalne i pozwala uniknąć pętli.
Alex Turpin
2
Nie potrzebujesz flagi, jeśli wszystko, co musisz wiedzieć, to czy „coś” jest w środku, możesz po prostu sprawdzić wartość indeksu skanowania z rozmiarem tablicy. Aby to zadziałało, należy oczywiście zadeklarować indeks var przed instrukcją for.
Alex
5
Te opcje wydają się działać teraz: vendors.forEach, vendors.filter, vendors.reduce
David Lozzi
1
co z JSON.stringify (dostawcy) .indexOf ('Magenic')! == -1
Last Breath
1
@LastBreath, który może dość łatwo dać fałszywy pozytyw, jeśli 'Magenic'jest gdzie indziej w obiekcie
Alex Turpin
947

Nie ma potrzeby wymyślania na nowo kołozapętlić, przynajmniej nie jawnie (używając funkcji strzałek , tylko nowoczesne przeglądarki ):

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

lub jeszcze lepiej :

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

EDYCJA: Jeśli potrzebujesz zgodności z kiepskimi przeglądarkami, najlepszym rozwiązaniem jest:

if (vendors.filter(function(e) { return e.Name === 'Magenic'; }).length > 0) {
  /* vendors contains the element we're looking for */
}
CAFxX
źródło
4
@Rocket, dlaczego edytowałeś moją odpowiedź? Składnia bez nawiasów klamrowych jest całkowicie poprawnym javascript .
CAFxX
4
Składnia „lambda” nadal nie działa w przeglądarce Chrome 16 (która nie jest kiepską przeglądarką).
Rocket Hazmat
27
To chyba zależy od twojej kiepskiej definicji. Ta składnia jest częścią javascript 1.8.
CAFxX,
7
Do zamknięcia wyrażenie używasz tutaj w pierwszych i drugich przykłady mają niestandardowe, nie używać! ostrzeżenie od Mozilli (patrz ten link). Działały one tylko w przeglądarce Firefox, a obecnie są przestarzałe i zostaną usunięte na rzecz funkcji strzałek .
doppelgreener
2
@ 7hibault, ponieważ somemoże spowodować zwarcie po znalezieniu obiektu name === "Magenic". Za pomocą filtersprawdzi każdy element do końca tablicy i utworzy nowe elementy tablicy spełniające warunek, a następnie sprawdzilength
adiga
93

Pętla nie jest wymagana. Trzy metody, które przychodzą na myśl:

Array.prototype.some ()

To jest najbardziej dokładna odpowiedź na twoje pytanie, tzn. „Sprawdź, czy coś istnieje”, co sugeruje wynik bool. Będzie to prawdą, jeśli będą jakieś „mageniczne” obiekty, w przeciwnym razie fałsz:

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

Array.prototype.filter ()

To zwróci tablicę wszystkich obiektów „Magenic”, nawet jeśli jest tylko jeden (zwróci tablicę jednoelementową):

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

Jeśli spróbujesz wymusić to na wartość logiczną, to nie zadziała, ponieważ pusta tablica (żadnych obiektów „magenicznych”) jest nadal prawdziwa. Więc po prostu użyj magenicVendors.lengthw swoim warunkowym.

Array.prototype.find ()

Zwróci pierwszy obiekt „Magenic” (lub undefinedjeśli go nie ma):

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

Zmusza to do logicznej zgody (każdy obiekt jest prawdomówny, undefinedjest fałszem).


Uwaga: zamiast nazwy dostawcy używam dostawcy [„Nazwa”] ze względu na dziwną obudowę nazw właściwości.

Uwaga 2: Nie ma powodu, aby używać luźnej równości (==) zamiast ścisłej równości (===) podczas sprawdzania nazwy.

boxtrain
źródło
5
Warto zauważyć, że pod maską wszystkie są zapętlone. Są one również wolniejsze obliczeniowo niż zwykłe zapętlanie i wykonywanie operacji.
ThePartyTurtle
Mogę również podzielić się tą miłością tutaj: stackoverflow.com/questions/21748670/... aby więcej osób takich jak ja nie przechodziło do tej starej strony i nie zakładało.
ThePartyTurtle
43

Akceptowana odpowiedź nadal działa, ale teraz mamy natywną metodę ECMAScript 6, [Array.find][1]aby osiągnąć ten sam efekt.

Cytując MDN:

Metoda find () zwraca wartość pierwszego elementu w tablicy, który spełnia podaną funkcję testową. W przeciwnym razie zwracana jest niezdefiniowana wartość.

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
}

Zobacz mój związek jsfiddle Jest polyfill dla IE dostarczane przez Mozillę

TeaCoder
źródło
2
Może być krótszy, jeśli to zrobisz return ele.id == '2', ale +1 za dobre rozwiązanie ES6.
Lye Fish,
Dobrze mieć świeżą odpowiedź :) Zastanawiam się, czy wydajność jest lepsza, czy nie niż powyższe odpowiedzi ...
Emidomenge
Myślę, że ważne jest, aby zwrócić uwagę, że zwracana wartość „data” (gdy ele.id pasuje do identyfikatora, takiego jak „21”), będzie sama w sobie elementem tablicy (w tym przypadku całym obiektem pozycji). Gdyby oczekiwano, że wynikiem zmiennej danych będzie „prawda” lub „fałsz” zamiast wartości fałszowania, byłbyś bardzo rozczarowany.
adamgede
Dzięki! Moje zadanie było trochę inne. Pobierz indeks Object in the Array => push if <0 || splice(index, 1)oto mój nieco zaktualizowany kod:const index = this.selected.indexOf(this.selected.find(s => s.id == passedObj.id))
Leonid Zadorozhnykh
29

Oto jak bym to zrobił

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

array.some()Metoda sprawdza, czy w tablicy jest co najmniej jedna wartość zgodna z kryteriami i zwraca wartość logiczną. Odtąd możesz iść z:

if (found) {
// do something
} else {
// do something else
}
Mirza Leka
źródło
22

Chyba że chcesz go zrestrukturyzować w ten sposób:

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

do czego możesz zrobić if(vendors.Magnetic)

Będziesz musiał zapętlić

Keith.Abramo
źródło
2
Na wypadek, gdyby nadal chciał utrzymać strukturę obiektu, aby użyć go gdzie indziej
Keith.Abramo
21

Zgodnie ze specyfikacją ECMAScript 6 można użyć findIndex.

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

magenicIndexbędzie przechowywać albo 0(który jest indeksem w tablicy), albo -1jeśli nie został znaleziony.

Lucas Bento
źródło
Aby uświadomić ludziom, że 0 nadal będzie pasować jako fałszywy wynik, jeśli zostanie to użyte jako warunek. Z tego powodu myślę, że find () jest lepszy, ponieważ otrzymujesz bardziej logiczną ocenę prawdziwości.
dhj
15

Jak OP zadał pytanie, czy klucz istnieje, czy nie .

Bardziej eleganckie rozwiązanie, które zwróci wartość logiczną za pomocą funkcji redukcji ES6

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

Uwaga: Początkowy parametr redukcji to a, falsea jeśli tablica ma klucz, zwróci wartość true.

Mam nadzieję, że pomoże to w lepszym i czystszym wdrażaniu kodu

Jay Chakra
źródło
1
Od kiedy !! [] oznacza fałsz?
Sergey
1
Dobry chwyt. Zaktualizowana odpowiedź przy użyciu zmniejsz :)
Jay Chakra,
1
To jest źle. Pierwszym parametrem reducejest akumulator, a nie vendorobiekt. Sprawdza się false.Name === "Magenic"w każdej pętli i zwraca false
adiga
@adiga: Poprawione.
Jay Chakra
1
Sprawdź także rozwiązanie Mirzy Leki. O wiele bardziej eleganckie rozwiązanie.
Jay Chakra
13

Nie da się tak naprawdę nie spojrzeć na przedmiot.

Prawdopodobnie powinieneś trochę zmienić swoją strukturę

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

Następnie możesz po prostu użyć go jako skrótu wyszukiwania.

vendors['Microsoft']; // 'DEF'
vendors['Apple']; // undefined
jAndy
źródło
6

Może być za późno, ale tablica javascript ma dwie metody someievery metodę, która zwraca wartość logiczną i może ci w tym pomóc.

Myślę, że somebyłoby najbardziej odpowiednie dla tego, co zamierzasz osiągnąć.

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

Niektóre potwierdzają, że dowolny obiekt w tablicy spełnia podany warunek.

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

Każdy potwierdza, że ​​wszystkie obiekty w tablicy spełniają dany warunek.

Akinjiola Toni
źródło
To nie działa const array1 = [{name:'Mike'},{name:'Alice'}]; console.log(array1.every(item => item.name !== 'Mike'));, powinno zwrócić wartość true
Thanwa Ch.
Przepraszam kolego, miałem na myśli some, zaktualizuje moją odpowiedź.
Akinjiola Toni
5

Musisz zapętlić, nie da się tego obejść.

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

Oczywiście możesz użyć biblioteki takiej jak linq.js, aby uczynić to bardziej przyjemnym:

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

(widzieć demo jsFiddle )

Wątpię, aby linq.js był szybszy niż prosta pętla, ale z pewnością jest bardziej elastyczny, gdy sprawy stają się trochę bardziej skomplikowane.

Tomalak
źródło
5

Testowanie elementów tablicy:

JS Oferuje funkcje tablicowe, które pozwalają stosunkowo łatwo to osiągnąć. Są to:

  1. Array.prototype.filter: Pobiera funkcję wywołania zwrotnego, która jest testem, a następnie tablica jest iterowana za pomocą wywołania zwrotnego i filtrowana zgodnie z tym wywołaniem zwrotnym. Zwracana jest nowa filtrowana tablica.
  2. Array.prototype.some: Pobiera funkcję wywołania zwrotnego, która jest testem, następnie tablica jest iterowana za pomocą wywołania zwrotnego, a jeśli jakikolwiek element przejdzie test, zwracana jest wartość logiczna true. W przeciwnym razie zwracana jest wartość false

Szczegóły najlepiej wyjaśnić na przykładzie:

Przykład:

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

Obsługa przeglądarki:

Te 2 funkcje są ES6funkcyjne, nie wszystkie przeglądarki mogą je obsługiwać. Aby temu zaradzić, możesz użyć polypełniacza. Oto wypełnienie dla Array.prototype.some(z 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;
  };
}

Willem van der Veen
źródło
4

jeśli używasz jquery, możesz skorzystać z grep, aby utworzyć tablicę ze wszystkimi pasującymi obiektami:

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

a następnie użyj tablicy wyników:

for (var i=0, l=results.length; i<l; i++) {
    console.log(results[i].ID);
}
Eitan
źródło
3

Popraw mnie, jeśli się mylę. Mogłem użyć forEachtakiej metody,

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

   }
});

Obecnie jestem do tego przyzwyczajony, ze względu na prostotę i zrozumiałe słowo. Dziękuję Ci.

Siddhesh Mishra
źródło
1
Uwaga: tutaj nie ma sensu powrotu
Edison
2

Możesz spróbować tego dla mnie.

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 } ]
smagać
źródło
To naprawdę stare pytanie i myślę, że jego aktualizacja ma obecnie najlepsze rozwiązanie.
Federico Galfione
1

Możesz użyć lodash . Jeśli biblioteka Lodash jest zbyt ciężka dla twojej aplikacji, rozważ wycinanie niepotrzebnej funkcji, która nie jest używana.

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

To tylko jeden ze sposobów, aby to zrobić. Innym może być:

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

console.log(arr);

Powyższy przykład można również przepisać bez użycia bibliotek takich jak:

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

Mam nadzieję, że moja odpowiedź pomaga.

Abhay Shiro
źródło
1

Wiele odpowiedzi tutaj jest dobrych i dość łatwych. Ale jeśli twoja tablica obiektów ma ustalony zestaw wartości, możesz użyć poniższej sztuczki:

Zamapuj całą nazwę w obiekcie.

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

Teraz ten brudnyObj możesz używać wielokrotnie bez pętli.

if(dirtyObj[vendor.Name]){
  console.log("Hey! I am available.");
}
jesusverma
źródło
1

Aby porównać jeden obiekt z drugim, łączę pętlę for in (używaną do przechodzenia między obiektami) i niektóre (). Nie musisz się martwić, że tablica wykracza poza granice itp., Więc oszczędza trochę kodu. Dokumentację na temat .some można znaleźć tutaj

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

Alternatywnym sposobem porównywania jednego obiektu z drugim jest użycie zagnieżdżonej pętli for z Object.keys (). Length, aby uzyskać liczbę obiektów w tablicy. Kod poniżej:

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

Aby odpowiedzieć na dokładne pytanie, jeśli po prostu szukasz wartości w obiekcie, możesz użyć pojedynczej pętli for in.

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');
    }
}
Blaszka
źródło
0

Alternatywnie możesz zrobić:

const find = (key, needle) => return !!~vendors.findIndex(v => (v[key] === needle));
BrunoWest
źródło
1
lepiej powiedz, dlaczego on może to zrobić
Azzabi Haythem
0

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

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

Wynik: bez2 ([{id: 1}, {id: 1}, {id: 2}], {id: 2})

behzad abbasi
źródło
Myślę, że chciałeś powiedzieć Wynik: [{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) {
   ...
}
użytkownik1665355
źródło
3
Proszę i trochę opisu i upewnij się, że podany przykład działa. (Filtr nie zmieni oryginalnej tablicy, ale ją sklonuje).
Moshe Simantov,
-1

Moje podejście do rozwiązania tego problemu polega na użyciu ES6 i stworzeniu funkcji, która sprawdza nas. Zaletą tej funkcji jest to, że można ją ponownie wykorzystać w całym projekcie, aby sprawdzić dowolną tablicę obiektów podanych jako keyivalue do sprawdzenia.

DOSKONAŁA ROZMOWA, ZOBACZmy KOD

Szyk

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

Funkcjonować

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

Zadzwoń / skorzystaj

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

const found = arrayIncludesInObj(ceos, "name", "Tim Bezos"); // false
rotimi-best
źródło
-4

Wolę iść z regex.

Jeśli Twój kod jest następujący,

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

Chciałbym polecić

/"Name":"Magenic"/.test(JSON.stringify(vendors))
sangwook kim
źródło
23
Niektórzy ludzie, gdy napotykają problem, myślą: „Wiem, użyję wyrażeń regularnych”. Teraz mają dwa problemy.
Craicerjack
Zapisz to poniżej, tylko dlatego, że możesz coś zrobić, nie oznacza, że ​​powinieneś.
Liam,