96

I have an array of objects:

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

I want to be able to search the object/array for where the key is "dinner", and see if it matches "sushi".

I know jQuery has $.inArray, but it doesn't seem to work on arrays of objects. Or maybe I'm wrong. indexOf also seems to only work on one array level.

Is there no function or existing code for this?

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Questioner
  • 7,133
  • 16
  • 61
  • 94
  • This has been asked before. You have to write your own function or use some other library. – Felix Kling Mar 03 '11 at 13:47
  • 1
    Please note that `Object` is reserved in Javascript, `Object` is the object object, ie the mother of all objects. – ase Mar 03 '11 at 14:15
  • 1
    question and accepted answer are not related to multidimensional arrays but more to 1-dimensional array filtering by its items' property values. => They didn't solve my problem "finding a value in a multidimensional array". – Martin Schneider Feb 09 '17 at 17:44

10 Answers10

225

If you have an array such as

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

You can use the filter method of an Array object:

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

In newer JavaScript implementations you can use a function expression:

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

You can search for people who have "dinner": "sushi" using a map

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

or a reduce

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

I'm sure you are able to generalize this to arbitrary keys and values!

ase
  • 13,231
  • 4
  • 34
  • 46
  • 7
    Just keep in mind that these solutions are part of ECMAScript 5 and not supported in IE8. http://kangax.github.com/es5-compat-table/ As much as I prefer @adamse's answer, alex's is more "old shitty browser" friendly. Not sure about performance though. – EasyCo Sep 25 '12 at 05:46
  • @SalmanA - nor the question or the solution is referring to jQuery. The javascript filter() is used, not jQuery-specific $.filter() - http://www.tutorialspoint.com/javascript/array_filter.htm – J.G.Sebring Jan 14 '13 at 14:14
  • As mentioned by EasyCo, the filter function is not supported in IE8. However, it is easily added to the Array prototype and thus usable in any browser with a small function at the beginning of your scripts. This is outlined in the [filter documentation](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter). It gives the exact function specified in ECMA-262, so it's literally the same thing. – dallin Mar 08 '13 at 17:20
  • 1
    I just added [an answer](http://stackoverflow.com/a/15622162/363701) which uses jQuery's `grep` method. Might make sense to roll into your answer as its the same concept as what you're doing, but jQuery dependant and shitty-browser friendly. – Zach Lysobey Mar 25 '13 at 18:34
  • Is there a reason I keep getting a reference error with my return variable? I tried the top two answers returning "x'' and it keeps saying it is undefined... – Evan Lalo Nov 17 '17 at 17:55
  • @EvanLalo you should ask a new question about this. – ase Nov 17 '17 at 17:57
18

jQuery has a built-in method jQuery.grep that works similarly to the ES5 filter function from @adamse's Answer and should work fine on older browsers.

Using adamse's example:

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

you can do the following

jQuery.grep(peoples, function (person) { return person.dinner == "sushi" });
  // => [{ "name": "john", "dinner": "sushi" }]
Community
  • 1
  • 1
Zach Lysobey
  • 14,959
  • 20
  • 95
  • 149
10

If you're going to be doing this search frequently, consider changing the format of your object so dinner actually is a key. This is kind of like assigning a primary clustered key in a database table. So, for example:

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

You can now easily access it like this: Object['sushi']['name']

Or if the object really is this simple (just 'name' in the object), you could just change it to:

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

And then access it like: Object['sushi'].

It's obviously not always possible or to your advantage to restructure your data object like this, but the point is, sometimes the best answer is to consider whether your data object is structured the best way. Creating a key like this can be faster and create cleaner code.

dallin
  • 8,775
  • 2
  • 36
  • 41
  • 1
    Love you answer, but i found problem with syntax: mine worked only like this: obj = { "pizza" : { "name" : "bob" }, "sushi" : { "name" : "john" } } alert (obj['pizza']['name']); but still. thanks! found what i was searching for! ) – aleXela Apr 09 '13 at 13:40
  • @alexela Thanks alexela! I updated my answer with your astute observation! I had just copied the example in the OP's post and neglected to add the quotes, but you're right - it won't work unless there are quotes at least around the values (assuming they are values and not variables). – dallin Apr 10 '13 at 20:18
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.

So long as -1 isn't ever a valid key.

alex
  • 479,566
  • 201
  • 878
  • 984
3

You can find the object in array with Alasql library:

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

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

Try this example in jsFiddle.

agershun
  • 4,077
  • 38
  • 41
  • 3
    I'm not sure this really deserved to be down voted. Sql like queries on collections become a lot easier to reason and write when the requirements become more complicated than a single filter or reduce call. Alasql is a pretty impressive library, but admittedly a little overkill for the example above. – TomDotTom Jul 30 '15 at 01:13
  • 1
    if the object itself originated from an SQL source, then this answer is pure genius. – edwardsmarkf Jan 16 '17 at 18:59
1

You can use a simple for in loop:

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

The following fiddle example puts all objects that contain dinner:sushi into an array:

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

Rotareti
  • 49,483
  • 23
  • 112
  • 108
1

There's already a lot of good answers here so why not one more, use a library like lodash or underscore :)

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
  • 6,238
  • 3
  • 41
  • 39
1

I had to search a nested sitemap structure for the first leaf item that machtes a given path. I came up with the following code just using .map() .filter() and .reduce. Returns the last item found that matches the path /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);

Edit 4n4904z07

Marc
  • 4,715
  • 3
  • 27
  • 34
0

We use object-scan for most of our data processing. It's conceptually very simple, but allows for a lot of cool stuff. Here is how you would solve your question

// 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' }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

Disclaimer: I'm the author of object-scan

vincent
  • 1,953
  • 3
  • 18
  • 24
0

If You want to find a specific object via search function just try something like this:

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

This is an example object:

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

Code will iterate and find the "user" array and will search for the object You seek inside.

My problem was when the array index changed every window refresh and it was either in 3rd or second array, but it does not matter.

Worked like a charm for Me!

In Your example it is a bit shorter:

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
  • 39
  • 1
  • 7