Jak znaleźć wartość w tablicy obiektów w JavaScript?

91

Mam tablicę obiektów:

Object = {
   1 : { name : bob , dinner : pizza },
   2 : { name : john , dinner : sushi },
   3 : { name : larry, dinner : hummus }
}

Chcę mieć możliwość przeszukania obiektu / tablicy pod kątem klucza „obiad” i sprawdzenia, czy pasuje do „sushi”.

Wiem, że jQuery ma $ .inArray, ale wygląda na to, że nie działa na tablicach obiektów. A może się mylę. indexOf również wydaje się działać tylko na jednym poziomie tablicy.

Czy nie ma do tego żadnej funkcji ani istniejącego kodu?

Indagator
źródło
Pytano o to wcześniej. Musisz napisać własną funkcję lub skorzystać z innej biblioteki.
Felix Kling
1
Należy pamiętać, że Objectw JavaScript zastrzeżony Objectjest obiekt obiekt, czyli matka wszystkich obiektów.
adamse
1
pytanie i zaakceptowana odpowiedź nie są związane z wielowymiarowymi tablicami, ale bardziej z jednowymiarowym filtrowaniem tablicy według wartości właściwości jej elementów. => Nie rozwiązali mojego problemu „znajdowanie wartości w wielowymiarowej tablicy”.
Martin Schneider

Odpowiedzi:

213

Jeśli masz tablicę, taką jak

var people = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

Możesz użyć filtermetody obiektu Array:

people.filter(function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]

W nowszych implementacjach JavaScript możesz użyć wyrażenia funkcyjnego:

people.filter(p => p.dinner == "sushi")
  // => [{ "name": "john", "dinner": "sushi" }]

Możesz wyszukiwać osoby, które "dinner": "sushi"używają domenymap

people.map(function (person) {
  if (person.dinner == "sushi") {
    return person
  } else {
    return null
  }
}); // => [null, { "name": "john", "dinner": "sushi" }, null]

lub a reduce

people.reduce(function (sushiPeople, person) {
  if (person.dinner == "sushi") {
    return sushiPeople.concat(person);
  } else {
    return sushiPeople
  }
}, []); // => [{ "name": "john", "dinner": "sushi" }]

Jestem pewien, że możesz to uogólnić na dowolne klucze i wartości!

adamse
źródło
7
Pamiętaj tylko, że te rozwiązania są częścią ECMAScript 5 i nie są obsługiwane w IE8. kangax.github.com/es5-compat-table O ile wolę odpowiedź @ adamse, alex jest bardziej przyjazny dla "starej, gównianej przeglądarki". Nie jestem jednak pewien co do wydajności.
EasyCo,
@SalmanA - ani pytanie, ani rozwiązanie nie odnoszą się do jQuery. Używany jest filtr javascript (), a nie specyficzna dla jQuery $ .filter () - tutorialspoint.com/javascript/array_filter.htm
Tapirboy
Jak wspomniało EasyCo, funkcja filtrowania nie jest obsługiwana w IE8. Jednak można go łatwo dodać do prototypu Array i dzięki temu można go używać w dowolnej przeglądarce z małą funkcją na początku skryptów. Jest to opisane w dokumentacji filtra . Daje dokładną funkcję określoną w ECMA-262, więc to dosłownie to samo.
dallin
1
Właśnie dodałem odpowiedź wykorzystującą grepmetodę jQuery . Może mieć sens zawarcie w Twojej odpowiedzi, ponieważ jest to ta sama koncepcja, co robisz, ale zależna od jQuery i przyjazna przeglądarkom.
Zach Lysobey,
Czy istnieje powód, dla którego ciągle otrzymuję błąd odwołania w mojej zmiennej zwracanej? Wypróbowałem dwie pierwsze odpowiedzi, zwracając „x” i ciągle mówi, że jest niezdefiniowane ...
Evan Lalo
18

jQuery ma wbudowaną metodę, jQuery.grepktóra działa podobnie do filterfunkcji ES5 z odpowiedzi @ adamse i powinna działać dobrze na starszych przeglądarkach.

Na przykładzie Adama:

var peoples = [
  { "name": "bob", "dinner": "pizza" },
  { "name": "john", "dinner": "sushi" },
  { "name": "larry", "dinner": "hummus" }
];

możesz wykonać następujące czynności

jQuery.grep(peoples, function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]
Zach Lysobey
źródło
10
var getKeyByDinner = function(obj, dinner) {
    var returnKey = -1;

    $.each(obj, function(key, info) {
        if (info.dinner == dinner) {
           returnKey = key;
           return false; 
        };   
    });

    return returnKey;       

}

jsFiddle .

O ile -1nie jest to nigdy prawidłowy klucz.

Alex
źródło
Prawie zagłosowałem za tym, ale nie było żadnego wyjaśnienia w poście.
mickmackusa,
10

Jeśli masz zamiar często przeprowadzać to wyszukiwanie, rozważ zmianę formatu obiektu, aby obiad był kluczowy. Przypomina to przypisywanie podstawowego klucza klastrowego w tabeli bazy danych. Na przykład:

Obj = { 'pizza' : { 'name' : 'bob' }, 'sushi' : { 'name' : 'john' } }

Możesz teraz łatwo uzyskać do niego dostęp w następujący sposób: Object['sushi']['name']

Lub jeśli obiekt jest naprawdę taki prosty (po prostu „nazwa” w obiekcie), możesz go po prostu zmienić na:

Obj = { 'pizza' : 'bob', 'sushi' : 'john' }

A następnie uzyskać do niego dostęp, takich jak: Object['sushi'].

Oczywiście nie zawsze jest możliwa lub korzystna zmiana struktury obiektu danych w ten sposób, ale chodzi o to, że czasami najlepszą odpowiedzią jest rozważenie, czy obiekt danych ma najlepszą strukturę. Utworzenie takiego klucza może być szybsze i stworzyć bardziej przejrzysty kod.

dallin
źródło
1
Uwielbiam odpowiadać, ale znalazłem problem ze składnią: mój działał tylko w ten sposób: obj = {"pizza": {"name": "bob"}, "sushi": {"name": "john"}} alert ( obj ['pizza'] ['nazwa']); ale nadal. dzięki! znalazłem to, czego szukałem! )
aleXela
@alexela Dzięki alexela! Zaktualizowałem moją odpowiedź twoją wnikliwą obserwacją! Właśnie skopiowałem przykład w poście OP i nie dodałem cudzysłowów, ale masz rację - nie zadziała, chyba że wokół wartości znajdują się cudzysłowy (zakładając, że są to wartości, a nie zmienne).
dallin
3

Obiekt można znaleźć w tablicy za pomocą biblioteki Alasql :

var data = [ { name : "bob" , dinner : "pizza" }, { name : "john" , dinner : "sushi" },
     { name : "larry", dinner : "hummus" } ];

var res = alasql('SELECT * FROM ? WHERE dinner="sushi"',[data]);

Wypróbuj ten przykład w jsFiddle .

agershun
źródło
3
Nie jestem pewien, czy to naprawdę zasługiwało na głosowanie w dół. Sql-like zapytania dotyczące kolekcji stają się dużo łatwiejsze do uzasadnienia i napisania, gdy wymagania stają się bardziej skomplikowane niż pojedynczy filtr lub wywołanie redukcji. Alasql to całkiem imponująca biblioteka, ale trzeba przyznać, że trochę przesada jak na powyższy przykład.
TomDotTom,
1
jeśli sam obiekt pochodzi ze źródła SQL, to ta odpowiedź jest czystym geniuszem.
edwardsmarkf
1

Możesz użyć prostej pętli for:

for (prop in Obj){
    if (Obj[prop]['dinner'] === 'sushi'){

        // Do stuff with found object. E.g. put it into an array:
        arrFoo.push(Obj[prop]);
    }
}

Poniższy przykład skrzypiec umieszcza wszystkie obiekty, które zawierają, dinner:sushiw tablicy:

https://jsfiddle.net/3asvkLn6/1/

Rotareti
źródło
1

Jest tu już wiele dobrych odpowiedzi, więc dlaczego nie jeszcze jednej, skorzystaj z biblioteki takiej jak lodash lub podkreślenie :)

obj = {
   1 : { name : 'bob' , dinner : 'pizza' },
   2 : { name : 'john' , dinner : 'sushi' },
   3 : { name : 'larry', dinner : 'hummus' }
}

_.where(obj, {dinner: 'pizza'})
>> [{"name":"bob","dinner":"pizza"}]
TomDotTom
źródło
0

Musiałem przeszukać zagnieżdżoną strukturę mapy witryny dla pierwszego elementu liścia, który obsługuje daną ścieżkę. Wymyśliłem następujący kod, używając tylko .map() .filter()i .reduce. Zwraca ostatni znaleziony element, który pasuje do ścieżki /c.

var sitemap = {
  nodes: [
    {
      items: [{ path: "/a" }, { path: "/b" }]
    },
    {
      items: [{ path: "/c" }, { path: "/d" }]
    },
    {
      items: [{ path: "/c" }, { path: "/d" }]
    }
  ]
};

const item = sitemap.nodes
  .map(n => n.items.filter(i => i.path === "/c"))
  .reduce((last, now) => last.concat(now))
  .reduce((last, now) => now);

Edytuj 4n4904z07

Marc
źródło
0

Jeśli chcesz znaleźć określony obiekt za pomocą funkcji wyszukiwania, spróbuj czegoś takiego:

    function findArray(value){

        let countLayer = dataLayer.length;
        for(var x = 0 ; x < countLayer ; x++){

            if(dataLayer[x].user){
                let newArr = dataLayer[x].user;
                let data = newArr[value];
                return data;
            }

        }

        return null;

    }

    findArray("id");

Oto przykładowy obiekt:

layerObj = {
    0: { gtm.start :1232542, event: "gtm.js"},
    1: { event: "gtm.dom", gtm.uniqueEventId: 52},
    2: { visitor id: "abcdef2345"},
    3: { user: { id: "29857239", verified: "Null", user_profile: "Personal", billing_subscription: "True", partners_user: "adobe"}
}

Kod dokona iteracji i znajdzie tablicę „user” oraz wyszuka obiekt, którego szukasz.

Mój problem polegał na tym, że indeks tablicy zmieniał się przy każdym odświeżaniu okna i znajdował się w trzeciej lub drugiej tablicy, ale to nie ma znaczenia.

Zadziałało dla mnie jak urok!

W Twoim przykładzie jest trochę krótszy:

function findArray(value){

    let countLayer = Object.length;
    for(var x = 0 ; x < countLayer ; x++){

        if(Object[x].dinner === value){
            return Object[x];
        }

    }

    return null;

}

findArray('sushi');
z3r0
źródło
0

Starałbym się nie wymyślać koła na nowo. Używamy skanowania obiektów do wszystkich naszych potrzeb związanych z przetwarzaniem danych. Jest koncepcyjnie bardzo prosty, ale pozwala na wiele fajnych rzeczy. Oto, jak możesz rozwiązać swoje konkretne pytanie

const objectScan = require('object-scan');

const findDinner = (dinner, data) => objectScan(['*'], {
  abort: true,
  rtn: 'value',
  filterFn: ({ value }) => value.dinner === dinner
})(data);

const data = {
  1: { name: 'bob', dinner: 'pizza' },
  2: { name: 'john', dinner: 'sushi' },
  3: { name: 'larry', dinner: 'hummus' }
};

console.log(findDinner('sushi', data));
// => { name: 'john', dinner: 'sushi' }
Vincent
źródło