thugsb
thugsb

Reputation: 23426

Search an array of JavaScript objects for an object with a matching value

I've got an array:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}, etc.]

I'm unable to change the structure of the array. I'm being passed an id of 45, and I want to get 'bar' for that object in the array.

How do I do this in JavaScript or using jQuery?

Upvotes: 2155

Views: 2515410

Answers (30)

Lasitha Lakmal
Lasitha Lakmal

Reputation: 880

Try this solution

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}, etc.]
var bar = myArray.find(ob=>(ob.id == 45)).bar;

Upvotes: 5

Pritesh Singh
Pritesh Singh

Reputation: 41

The below code will help you to search values from nested objects also in your data.

const updatedData = myArrayOfObjects.filter((obj: any) => Object.values(obj).some((val: any) => {
   if (typeof (val) == typeof ("str")) {
      return val.toString().includes(Search)
   } else {
      return Object.values(val).some((newval: any) => {
         if (newval !== null) {
            return newval.toString().includes(Search)
         }
      })
   }
}))

Upvotes: 0

Nick Parsons
Nick Parsons

Reputation: 50639

As others have pointed out, .find() is the way to go when looking for one object within your array. However, if your object cannot be found using this method, your program will crash:

const myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
const res = myArray.find(x => x.id === '100').foo; // Uh oh!
/*
Error:
"Uncaught TypeError: Cannot read property 'foo' of undefined"
or in newer chrome versions:
Uncaught TypeError: Cannot read properties of undefined (reading 'foo')
*/

This can be fixed by checking whether the result of .find() is defined before using .foo on it. Modern JS allows us to do this easily with optional chaining, returning undefined if the object cannot be found, rather than crashing your code:

const myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
const res = myArray.find(x => x.id === '100')?.foo; // No error!
console.log(res); // undefined when the object cannot be found

Upvotes: 30

Jonas Wilms
Jonas Wilms

Reputation: 138234

If you do this multiple times, you may set up a Map (ES6):

const map = new Map( myArray.map(el => [el.id, el]) );

Then you can simply do a O(1) lookup:

map.get(27).foo

Upvotes: 28

Michał Perłakowski
Michał Perłakowski

Reputation: 92461

Use the find() method:

myArray.find(x => x.id === '45').foo;

From MDN:

The find() method returns the first value in the array, if an element in the array satisfies the provided testing function. Otherwise undefined is returned.


If you want to find its index instead, use findIndex():

myArray.findIndex(x => x.id === '45');

From MDN:

The findIndex() method returns the index of the first element in the array that satisfies the provided testing function. Otherwise -1 is returned.


If you want to get an array of matching elements, use the filter() method instead:

myArray.filter(x => x.id === '45');

This will return an array of objects. If you want to get an array of foo properties, you can do this with the map() method:

myArray.filter(x => x.id === '45').map(x => x.foo);

Side note: methods like find() or filter(), and arrow functions are not supported by older browsers (like IE), so if you want to support these browsers, you should transpile your code using Babel (with the polyfill).

Upvotes: 2205

Rúnar Berg
Rúnar Berg

Reputation: 4812

ECMAScript 2015 (JavaScript ES6) provides the find() method on arrays:

var myArray = [
 {id:1, name:"bob"},
 {id:2, name:"dan"},
 {id:3, name:"barb"},
]

// grab the Array item which matchs the id "2"
var item = myArray.find(item => item.id === 2);

// print
console.log(item.name);

It works without external libraries. But if you want older browser support you might want to include this polyfill.

Upvotes: 238

Kamil Kiełczewski
Kamil Kiełczewski

Reputation: 92347

Performance

Today 2020.06.20 I perform test on MacOs High Sierra on Chrome 81.0, Firefox 77.0 and Safari 13.1 for chosen solutions.

Conclusions for solutions which use precalculations

Solutions with precalculations (K,L) are (much much) faster than other solutions and will not be compared with them - probably they are use some special build-in browser optimisations

  • surprisingly on Chrome and Safari solution based on Map (K) are much faster than solution based on object {} (L)
  • surprisingly on Safari for small arrays solution based on object {} (L) is slower than traditional for (E)
  • surprisingly on Firefox for small arrays solution based on Map (K) is slower than traditional for (E)

Conclusions when searched objects ALWAYS exists

  • solution which use traditional for (E) is fastest for small arrays and fast for big arrays
  • solution using cache (J) is fastest for big arrays - surprisingly for small arrays is medium fast
  • solutions based on find (A) and findIndex (B) are fast for small arras and medium fast on big arrays
  • solution based on $.map (H) is slowest on small arrays
  • solution based on reduce (D) is slowest on big arrays

enter image description here

Conclusions when searched objects NEVER exists

  • solution based on traditional for (E) is fastest on small and big arrays (except Chrome-small arrays where it is second fast)
  • solution based on reduce (D) is slowest on big arrays
  • solution which use cache (J) is medium fast but can be speed up if we save in cache also keys which have null values (which was not done here because we want to avoid unlimited memory consumption in cache in case when many not existing keys will be searched)

enter image description here

Details

For solutions

  • without precalculations: A B C D E F G H I J (the J solution use 'inner' cache and it speed depend on how often searched elements will repeat)
  • with precalculations K L

I perform four tests. In tests I want to find 5 objects in 10 loop iterations (the objects ID not change during iterations) - so I call tested method 50 times but only first 5 times have unique id values:

  • small array (10 elements) and searched object ALWAYS exists - you can perform it HERE
  • big array (10k elements) and searched object ALWAYS exist - you can perform it HERE
  • small array (10 elements) and searched object NEVER exists - you can perform it HERE
  • big array (10k elements) and searched object NEVER exists - you can perform it HERE

Tested codes are presented below

function A(arr, id) {
  return arr.find(o=> o.id==id);
}

function B(arr, id) {
  let idx= arr.findIndex(o=> o.id==id);
  return arr[idx];
}

function C(arr, id) {
  return arr.filter(o=> o.id==id)[0];
}

function D(arr, id) {
  return arr.reduce((a, b) => (a.id==id && a) || (b.id == id && b));
}

function E(arr, id) {
  for (var i = 0; i < arr.length; i++) if (arr[i].id==id) return arr[i];
  return null;
}

function F(arr, id) {
  var retObj ={};
  $.each(arr, (index, obj) => {
    if (obj.id == id) { 
      retObj = obj;
      return false;
    }
  });
  return retObj;
}

function G(arr, id) {
  return $.grep(arr, e=> e.id == id )[0];
}

function H(arr, id) {
  return $.map(myArray, function(val) {
    return val.id == id ? val : null;
  })[0];
}

function I(arr, id) {
  return _.find(arr, o => o.id==id);
}

let J = (()=>{
  let cache = new Map();
  return function J(arr,id,el=null) { 
    return cache.get(id) || (el=arr.find(o=> o.id==id), cache.set(id,el), el);
  }
})();

function K(arr, id) {
  return mapK.get(id)
}

function L(arr, id) {
  return mapL[id];
}



// -------------
// TEST
// -------------

console.log('Find id=5');

myArray = [...Array(10)].map((x,i)=> ({'id':`${i}`, 'foo':`bar_${i}`}));
const mapK = new Map( myArray.map(el => [el.id, el]) );
const mapL = {}; myArray.forEach(el => mapL[el.id]=el);



[A,B,C,D,E,F,G,H,I,J,K,L].forEach(f=> console.log(`${f.name}: ${JSON.stringify(f(myArray, '5'))}`));

console.log('Whole array',JSON.stringify(myArray));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

This snippet only presents tested codes

Example tests results for Chrome for small array where searched objects always exists

enter image description here

Upvotes: 36

Kamil Kiełczewski
Kamil Kiełczewski

Reputation: 92347

Dynamic cached find

In this solution, when we search for some object, we save it in cache. This is middle point between "always search solutions" and "create hash-map for each object in precalculations".

let cachedFind = (()=>{
  let cache = new Map();
  return (arr,id,el=null) => 
    cache.get(id) || (el=arr.find(o=> o.id==id), cache.set(id,el), el);
})();


// ---------
// TEST
// ---------

let myArray = [...Array(100000)].map((x,i)=> ({'id':`${i}`, 'foo':`bar_${i}`}));

// example usage

console.log( cachedFind(myArray,'1234').foo );





// Benchmark

let bench = (id) => {
  console.time   ('time for '+id ); 
  console.log    ( cachedFind(myArray,id).foo );  // FIND
  console.timeEnd('time for '+id );
}

console.log('----- no cached -----');
bench(50000);
bench(79980);
bench(99990);
console.log('-----  cached   -----');
bench(79980); // cached
bench(99990); // cached

Upvotes: 4

TLbiz
TLbiz

Reputation: 497

We can use Jquery methods $.each()/$.grep()

var data= [];
$.each(array,function(i){if(n !== 5 && i > 4){data.push(item)}}

or

var data = $.grep(array, function( n, i ) {
  return ( n !== 5 && i > 4 );
});

use ES6 syntax:

Array.find, Array.filter, Array.forEach, Array.map

Or use Lodash https://lodash.com/docs/4.17.10#filter, Underscore https://underscorejs.org/#filter

Upvotes: 7

maheshwaghmare
maheshwaghmare

Reputation: 2192

Recently, I have to face the same thing in which I need to search the string from a huge array.

After some search I found It'll be easy to handle with simple code:

Code:

var items = mydata.filter(function(item){
    return item.word.toLowerCase().startsWith( 'gk );
})

See https://jsfiddle.net/maheshwaghmare/cfx3p40v/4/

Serach from 20k strings

Upvotes: 9

Guffa
Guffa

Reputation: 700152

As you are already using jQuery, you can use the grep function which is intended for searching an array:

var result = $.grep(myArray, function(e){ return e.id == id; });

The result is an array with the items found. If you know that the object is always there and that it only occurs once, you can just use result[0].foo to get the value. Otherwise you should check the length of the resulting array. Example:

if (result.length === 0) {
  // no result found
} else if (result.length === 1) {
  // property found, access the foo property using result[0].foo
} else {
  // multiple items found
}

Upvotes: 1502

Vu Truong
Vu Truong

Reputation: 1883

My way to find index of array:

index = myArray.map((i) => i.id).indexOf(value_of_id);
item = myArray[index];

Upvotes: -4

Savan Kaneriya
Savan Kaneriya

Reputation: 79

More generic and short

function findFromArray(array,key,value) {
        return array.filter(function (element) {
            return element[key] == value;
        }).shift();
}

in your case Ex. var element = findFromArray(myArray,'id',45) that will give you the whole element.

Upvotes: 7

Sumit Ridhal
Sumit Ridhal

Reputation: 1419

Use Array.prototype.filter() function.

DEMO: https://jsfiddle.net/sumitridhal/r0cz0w5o/4/

JSON

var jsonObj =[
 {
  "name": "Me",
  "info": {
   "age": "15",
   "favColor": "Green",
   "pets": true
  }
 },
 {
  "name": "Alex",
  "info": {
   "age": "16",
   "favColor": "orange",
   "pets": false
  }
 },
{
  "name": "Kyle",
  "info": {
   "age": "15",
   "favColor": "Blue",
   "pets": false
  }
 }
];

FILTER

var getPerson = function(name){
    return jsonObj.filter(function(obj) {
      return obj.name === name;
    });
}

Upvotes: 5

Dan W
Dan W

Reputation: 762

Here's how I'd go about it in pure JavaScript, in the most minimal manner I can think of that works in ECMAScript 3 or later. It returns as soon as a match is found.

var getKeyValueById = function(array, key, id) {
    var testArray = array.slice(), test;
    while(test = testArray.pop()) {
        if (test.id === id) {
            return test[key];
        }
    }
    // return undefined if no matching id is found in array
    return;
}

var myArray = [{'id':'73', 'foo':'bar'}, {'id':'45', 'foo':'bar'}]
var result = getKeyValueById(myArray, 'foo', '45');

// result is 'bar', obtained from object with id of '45'

Upvotes: 7

Tom
Tom

Reputation: 8180

While there are many correct answers here, many of them do not address the fact that this is an unnecessarily expensive operation if done more than once. In an extreme case this could be the cause of real performance problems.

In the real world, if you are processing a lot of items and performance is a concern it's much faster to initially build a lookup:

var items = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];

var lookup = items.reduce((o,i)=>o[i.id]=o,{});

you can then get at items in fixed time like this :

var bar = o[id];

You might also consider using a Map instead of an object as the lookup: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Map

Upvotes: 16

kaizer1v
kaizer1v

Reputation: 908

You can do this even in pure JavaScript by using the in built "filter" function for arrays:

Array.prototype.filterObjects = function(key, value) {
    return this.filter(function(x) { return x[key] === value; })
}

So now simply pass "id" in place of key and "45" in place of value, and you will get the full object matching an id of 45. So that would be,

myArr.filterObjects("id", "45");

Upvotes: 4

pimvdb
pimvdb

Reputation: 154818

I think the easiest way would be the following, but it won't work on Internet Explorer 8 (or earlier):

var result = myArray.filter(function(v) {
    return v.id === '45'; // Filter out the appropriate one
})[0].foo; // Get result and access the foo property

Upvotes: 144

stevenspiel
stevenspiel

Reputation: 5999

Building on the accepted answer:

jQuery:

var foo = $.grep(myArray, function(e){ return e.id === foo_id})
myArray.pop(foo)

Or CoffeeScript:

foo = $.grep myArray, (e) -> e.id == foo_id
myArray.pop foo

Upvotes: 5

soytian
soytian

Reputation: 318

This solution may helpful as well:

Array.prototype.grep = function (key, value) {
    var that = this, ret = [];
    this.forEach(function (elem, index) {
        if (elem[key] === value) {
            ret.push(that[index]);
        }
    });
    return ret.length < 2 ? ret[0] : ret;
};
var bar = myArray.grep("id","45");

I made it just like $.grep and if one object is find out, function will return the object, rather than an array.

Upvotes: 3

aggaton
aggaton

Reputation: 3350

As long as the browser supports ECMA-262, 5th edition (December 2009), this should work, almost one-liner:

var bFound = myArray.some(function (obj) {
    return obj.id === 45;
});

Upvotes: 8

volumexxx
volumexxx

Reputation: 55

Use:

var retObj ={};
$.each(ArrayOfObjects, function (index, obj) {

        if (obj.id === '5') { // id.toString() if it is int

            retObj = obj;
            return false;
        }
    });
return retObj;

It should return an object by id.

Upvotes: 3

deepflame
deepflame

Reputation: 928

You may try out Sugarjs from http://sugarjs.com/.

It has a very sweet method on Arrays, .find. So you can find an element like this:

array.find( {id: 75} );

You may also pass an object with more properties to it to add another "where-clause".

Note that Sugarjs extends native objects, and some people consider this very evil...

Upvotes: 8

hunter
hunter

Reputation: 63502

You can get this easily using the map() function:

myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];

var found = $.map(myArray, function(val) {
    return val.id == 45 ? val.foo : null;
});

//found[0] == "bar";

Working example: http://jsfiddle.net/hunter/Pxaua/

Upvotes: 17

Zirak
Zirak

Reputation: 39808

Iterate over any item in the array. For every item you visit, check that item's id. If it's a match, return it.

If you just want teh codez:

function getId(array, id) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].id === id) {
            return array[i];
        }
    }
    return null; // Nothing found
}

And the same thing using ECMAScript 5's Array methods:

function getId(array, id) {
    var obj = array.filter(function (val) {
        return val.id === id;
    });

    // Filter returns an array, and we just want the matching item.
    return obj[0];
}

Upvotes: 8

laggingreflex
laggingreflex

Reputation: 34627

Using native Array.reduce

var array = [ {'id':'73' ,'foo':'bar'} , {'id':'45' ,'foo':'bar'} , ];
var id = 73;
var found = array.reduce(function(a, b){
    return (a.id==id && a) || (b.id == id && b)
});

returns the object element if found, otherwise false

Upvotes: 17

Danilo Colasso
Danilo Colasso

Reputation: 2381

myArray.filter(function(a){ return a.id == some_id_you_want })[0]

Upvotes: 48

ramya
ramya

Reputation: 275

Consider "axesOptions" to be array of objects with an object format being {:field_type => 2, :fields => [1,3,4]}

function getFieldOptions(axesOptions,choice){
  var fields=[]
  axesOptions.each(function(item){
    if(item.field_type == choice)
        fields= hashToArray(item.fields)
  });
  return fields;
}

Upvotes: -2

Manu
Manu

Reputation: 599

Shortest,

var theAnswerObj = _.findWhere(array, {id : 42});

Upvotes: 0

quincyaft
quincyaft

Reputation: 55

I really liked the answer provided by Aaron Digulla but needed to keep my array of objects so I could iterate through it later. So I modified it to

	var indexer = {};
	for (var i = 0; i < array.length; i++) {
	    indexer[array[i].id] = parseInt(i);
	}
	
	//Then you can access object properties in your array using 
	array[indexer[id]].property

Upvotes: 3

Related Questions