What is the most concise and efficient way to find out if a JavaScript array contains a value?
This is the only way I know to do it:
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Is there a better and more concise way to accomplish this?
This is very closely related to Stack Overflow question Best way to find an item in a JavaScript Array? which addresses finding objects in an array using indexOf.
Modern browsers have Array#includes, which does exactly that and is widely supported by everyone except IE:
console.log(['joe', 'jane', 'mary'].includes('jane')); //true
You can also use Array#indexOf, which is less direct, but doesn't require polyfills for outdated browsers.
console.log(['joe', 'jane', 'mary'].indexOf('jane') >= 0); //true
Many frameworks also offer similar methods:
jQuery: $.inArray(value, array, [fromIndex])
Underscore.js: _.contains(array, value) (also aliased as _.include and _.includes)
Dojo Toolkit: dojo.indexOf(array, value, [fromIndex, findLast])
Prototype: array.indexOf(value)
MooTools: array.indexOf(value)
MochiKit: findValue(array, value)
MS Ajax: array.indexOf(value)
Ext: Ext.Array.contains(array, value)
Lodash: _.includes(array, value, [from]) (is _.contains prior 4.0.0)
Ramda: R.includes(value, array)
Notice that some frameworks implement this as a function, while others add the function to the array prototype.
Update from 2019: This answer is from 2008 (11 years old!) and is not relevant for modern JS usage. The promised performance improvement was based on a benchmark done in browsers of that time. It might not be relevant to modern JS execution contexts. If you need an easy solution, look for other answers. If you need the best performance, benchmark for yourself in the relevant execution environments.
As others have said, the iteration through the array is probably the best way, but it has been proven that a decreasing while loop is the fastest way to iterate in JavaScript. So you may want to rewrite your code as follows:
function contains(a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Of course, you may as well extend Array prototype:
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
And now you can simply use the following:
alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
indexOf maybe, but it's a "JavaScript extension to the ECMA-262 standard; as such it may not be present in other implementations of the standard."
Example:
[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1
AFAICS Microsoft does not offer some kind of alternative to this, but you can add similar functionality to arrays in Internet Explorer (and other browsers that don't support indexOf) if you want to, as a quick Google search reveals (for example, this one).
The top answers assume primitive types but if you want to find out if an array contains an object with some trait, Array.prototype.some() is an elegant solution:
const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]
items.some(item => item.a === '3') // returns true
items.some(item => item.a === '4') // returns false
The nice thing about it is that the iteration is aborted once the element is found so unnecessary iteration cycles are spared.
Also, it fits nicely in an if statement since it returns a boolean:
if (items.some(item => item.a === '3')) {
// do something
}
* As jamess pointed out in the comment, at the time of this answer, September 2018, Array.prototype.some() is fully supported: caniuse.com support table
ECMAScript 7 introduces Array.prototype.includes.
It can be used like this:
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
It also accepts an optional second argument fromIndex:
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
Unlike indexOf, which uses Strict Equality Comparison, includes compares using SameValueZero equality algorithm. That means that you can detect if an array includes a NaN:
[1, 2, NaN].includes(NaN); // true
Also unlike indexOf, includes does not skip missing indices:
new Array(5).includes(undefined); // true
It can be polyfilled to make it work on all browsers.
Let's say you've defined an array like so:
const array = [1, 2, 3, 4]
Below are three ways of checking whether there is a 3 in there. All of them return either true or false.
Native Array method (since ES2016) (compatibility table)
array.includes(3) // true
As custom Array method (pre ES2016)
// Prefixing the method with '_' to avoid name clashes
Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }})
array._includes(3) // true
Simple function
const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true
Here's a JavaScript 1.6 compatible implementation of Array.indexOf:
if (!Array.indexOf) {
Array.indexOf = [].indexOf ?
function(arr, obj, from) {
return arr.indexOf(obj, from);
} :
function(arr, obj, from) { // (for IE6)
var l = arr.length,
i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0;
i = i < 0 ? 0 : i;
for (; i < l; i++) {
if (i in arr && arr[i] === obj) {
return i;
}
}
return -1;
};
}
Use:
function isInArray(array, search)
{
return array.indexOf(search) >= 0;
}
// Usage
if(isInArray(my_array, "my_value"))
{
//...
}
Extending the JavaScript Array object is a really bad idea because you introduce new properties (your custom methods) into for-in loops which can break existing scripts. A few years ago the authors of the Prototype library had to re-engineer their library implementation to remove just this kind of thing.
If you don't need to worry about compatibility with other JavaScript running on your page, go for it, otherwise, I'd recommend the more awkward, but safer free-standing function solution.
Performance
Today 2020.01.07 I perform tests on MacOs HighSierra 10.13.6 on Chrome v78.0.0, Safari v13.0.4 and Firefox v71.0.0 for 15 chosen solutions. Conclusions
solutions based on JSON, Set and surprisingly find (K,N,O) are slowest on all browsers
the es6 includes (F) is fast only on chrome
the solutions based on for (C,D) and indexOf (G,H) are quite-fast on all browsers on small and big arrays so probably they are best choice for efficient solution
the solutions where index decrease during loop, (B) is slower probably because the way of CPU cache works.
I also run test for big array when searched element was on position 66% of array length, and solutions based on for (C,D,E) gives similar results (~630 ops/sec - but the E on safari and firefox was 10-20% slower than C and D)
Results
Details
I perform 2 tests cases: for array with 10 elements, and array with 1 milion elements. In both cases we put searched element in the array middle.
let log = (name,f) => console.log(`${name}: 3-${f(arr,'s10')} 's7'-${f(arr,'s7')} 6-${f(arr,6)} 's3'-${f(arr,'s3')}`)
let arr = [1,2,3,4,5,'s6','s7','s8','s9','s10'];
//arr = new Array(1000000).fill(123); arr[500000]=7;
function A(a, val) {
var i = -1;
var n = a.length;
while (i++<n) {
if (a[i] === val) {
return true;
}
}
return false;
}
function B(a, val) {
var i = a.length;
while (i--) {
if (a[i] === val) {
return true;
}
}
return false;
}
function C(a, val) {
for (var i = 0; i < a.length; i++) {
if (a[i] === val) return true;
}
return false;
}
function D(a,val)
{
var len = a.length;
for(var i = 0 ; i < len;i++)
{
if(a[i] === val) return true;
}
return false;
}
function E(a, val){
var n = a.length-1;
var t = n/2;
for (var i = 0; i <= t; i++) {
if (a[i] === val || a[n-i] === val) return true;
}
return false;
}
function F(a,val) {
return a.includes(val);
}
function G(a,val) {
return a.indexOf(val)>=0;
}
function H(a,val) {
return !!~a.indexOf(val);
}
function I(a, val) {
return a.findIndex(x=> x==val)>=0;
}
function J(a,val) {
return a.some(x=> x===val);
}
function K(a, val) {
const s = JSON.stringify(val);
return a.some(x => JSON.stringify(x) === s);
}
function L(a,val) {
return !a.every(x=> x!==val);
}
function M(a, val) {
return !!a.find(x=> x==val);
}
function N(a,val) {
return a.filter(x=>x===val).length > 0;
}
function O(a, val) {
return new Set(a).has(val);
}
log('A',A);
log('B',B);
log('C',C);
log('D',D);
log('E',E);
log('F',F);
log('G',G);
log('H',H);
log('I',I);
log('J',J);
log('K',K);
log('L',L);
log('M',M);
log('N',N);
log('O',O);
This shippet only presents functions used in performance tests - it not perform tests itself!
Array small - 10 elements
You can perform tests in your machine HERE
Array big - 1.000.000 elements
You can perform tests in your machine HERE
One-liner:
function contains(arr, x) {
return arr.filter(function(elem) { return elem == x }).length > 0;
}
Thinking out of the box for a second, if you are making this call many many times, it is vastly more efficient to use an associative array a Map to do lookups using a hash function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
I use the following:
Array.prototype.contains = function (v) {
return this.indexOf(v) > -1;
}
var a = [ 'foo', 'bar' ];
a.contains('foo'); // true
a.contains('fox'); // false
function contains(a, obj) {
return a.some(function(element){return element == obj;})
}
Array.prototype.some() was added to the ECMA-262 standard in the 5th edition
If you are using JavaScript 1.6 or later (Firefox 1.5 or later) you can use Array.indexOf. Otherwise, I think you are going to end up with something similar to your original code.
A hopefully faster bidirectional indexOf / lastIndexOf alternative
2015
While the new method includes is very nice, the support is basically zero for now.
It's a long time that I was thinking of a way to replace the slow indexOf/lastIndexOf functions.
A performant way has already been found, looking at the top answers. From those I chose the contains function posted by #Damir Zekic which should be the fastest one. But it also states that the benchmarks are from 2008 and so are outdated.
I also prefer while over for, but for not a specific reason I ended writing the function with a for loop. It could be also done with a while --.
I was curious if the iteration was much slower if I check both sides of the array while doing it. Apparently no, and so this function is around two times faster than the top voted ones. Obviously it's also faster than the native one. This is in a real world environment, where you never know if the value you are searching is at the beginning or at the end of the array.
When you know you just pushed an array with a value, using lastIndexOf remains probably the best solution, but if you have to travel through big arrays and the result could be everywhere, this could be a solid solution to make things faster.
Bidirectional indexOf/lastIndexOf
function bidirectionalIndexOf(a, b, c, d, e){
for(c=a.length,d=c*1; c--; ){
if(a[c]==b) return c; //or this[c]===b
if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
}
return -1
}
//Usage
bidirectionalIndexOf(array,'value');
Performance test
https://jsbench.me/7el1b8dj80
As a test I created an array with 100k entries.
Three queries: at the beginning, in the middle & at the end of the array.
I hope you also find this interesting and test the performance.
Note: As you can see I slightly modified the contains function to reflect the indexOf & lastIndexOf output (so basically true with the index and false with -1). That shouldn't harm it.
The array prototype variant
Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
for(c=this.length,d=c*1; c--; ){
if(this[c]==b) return c; //or this[c]===b
if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
}
return -1
},writable:false, enumerable:false});
// Usage
array.bidirectionalIndexOf('value');
The function can also be easily modified to return true or false or even the object, string or whatever it is.
And here is the while variant:
function bidirectionalIndexOf(a, b, c, d){
c=a.length; d=c-1;
while(c--){
if(b===a[c]) return c;
if(b===a[d-c]) return d-c;
}
return c
}
// Usage
bidirectionalIndexOf(array,'value');
How is this possible?
I think that the simple calculation to get the reflected index in an array is so simple that it's two times faster than doing an actual loop iteration.
Here is a complex example doing three checks per iteration, but this is only possible with a longer calculation which causes the slowdown of the code.
https://web.archive.org/web/20151019160219/http://jsperf.com/bidirectionalindexof/2
function inArray(elem,array)
{
var len = array.length;
for(var i = 0 ; i < len;i++)
{
if(array[i] == elem){return i;}
}
return -1;
}
Returns array index if found, or -1 if not found
If you are checking repeatedly for existence of an object in an array you should maybe look into
Keeping the array sorted at all times by doing insertion sort in your array (put new objects in on the right place)
Make updating objects as remove+sorted insert operation and
Use a binary search lookup in your contains(a, obj).
We use this snippet (works with objects, arrays, strings):
/*
* #function
* #name Object.prototype.inArray
* #description Extend Object prototype within inArray function
*
* #param {mix} needle - Search-able needle
* #param {bool} searchInKey - Search needle in keys?
*
*/
Object.defineProperty(Object.prototype, 'inArray',{
value: function(needle, searchInKey){
var object = this;
if( Object.prototype.toString.call(needle) === '[object Object]' ||
Object.prototype.toString.call(needle) === '[object Array]'){
needle = JSON.stringify(needle);
}
return Object.keys(object).some(function(key){
var value = object[key];
if( Object.prototype.toString.call(value) === '[object Object]' ||
Object.prototype.toString.call(value) === '[object Array]'){
value = JSON.stringify(value);
}
if(searchInKey){
if(value === needle || key === needle){
return true;
}
}else{
if(value === needle){
return true;
}
}
});
},
writable: true,
configurable: true,
enumerable: false
});
Usage:
var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first"); //true
a.inArray("foo"); //false
a.inArray("foo", true); //true - search by keys
a.inArray({three: "third"}); //true
var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one"); //true
b.inArray('foo'); //false
b.inArray({foo: 'val'}) //true
b.inArray("{foo: 'val'}") //false
var c = "String";
c.inArray("S"); //true
c.inArray("s"); //false
c.inArray("2", true); //true
c.inArray("20", true); //false
Solution that works in all modern browsers:
function contains(arr, obj) {
const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
return arr.some(item => JSON.stringify(item) === stringifiedObj);
}
Usage:
contains([{a: 1}, {a: 2}], {a: 1}); // true
IE6+ solution:
function contains(arr, obj) {
var stringifiedObj = JSON.stringify(obj)
return arr.some(function (item) {
return JSON.stringify(item) === stringifiedObj;
});
}
// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
Array.prototype.some = function (tester, that /*opt*/) {
for (var i = 0, n = this.length; i < n; i++) {
if (i in this && tester.call(that, this[i], i, this)) return true;
} return false;
};
}
Usage:
contains([{a: 1}, {a: 2}], {a: 1}); // true
Why to use JSON.stringify?
Array.indexOf and Array.includes (as well as most of the answers here) only compare by reference and not by value.
[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object
Bonus
Non-optimized ES6 one-liner:
[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true
Note:
Comparing objects by value will work better if the keys are in the same order, so to be safe you might sort the keys first with a package like this one: https://www.npmjs.com/package/sort-keys
Updated the contains function with a perf optimization. Thanks itinance for pointing it out.
There are a couple of method which makes this easy to achieve (includes, some, find, findIndex)
const array = [1, 2, 3, 4, 5, 6, 7];
console.log(array.includes(3));
//includes() determines whether an array includes a certain value among its entries
console.log(array.some(x => x === 3));
//some() tests if at least one element in the array passes the test implemented by the provided function
console.log(array.find(x => x === 3) ? true : false);
//find() returns the value of the first element in the provided array that satisfies the provided testing function
console.log(array.findIndex(x => x === 3) > -1);
//findIndex() returns the index of the first element in the array that satisfies the provided testing function, else returning -1.
More about includes, some, find, findIndex
Use lodash's some function.
It's concise, accurate and has great cross platform support.
The accepted answer does not even meet the requirements.
Requirements: Recommend most concise and efficient way to find out if a JavaScript array contains an object.
Accepted Answer:
$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1
My recommendation:
_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true
Notes:
$.inArray works fine for determining whether a scalar value exists in an array of scalars...
$.inArray(2, [1,2])
> 1
... but the question clearly asks for an efficient way to determine if an object is contained in an array.
In order to handle both scalars and objects, you could do this:
(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)
Simple solution for this requirement is using find()
If you're having array of objects like below,
var users = [{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "admin"},
{id: "105", name: "user"}];
Then you can check whether the object with your value is already present or not:
let data = users.find(object => object['id'] === '104');
if data is null then no admin, else it will return the existing object like:
{id: "104", name: "admin"}
Then you can find the index of that object in the array and replace the object using the code:
let indexToUpdate = users.indexOf(data);
let newObject = {id: "104", name: "customer"};
users[indexToUpdate] = newObject;//your new object
console.log(users);
you will get value like:
[{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "customer"},
{id: "105", name: "user"}];
ECMAScript 6 has an elegant proposal on find.
The find method executes the callback function once for each element
present in the array until it finds one where callback returns a true
value. If such an element is found, find immediately returns the value
of that element. Otherwise, find returns undefined. callback is
invoked only for indexes of the array which have assigned values; it
is not invoked for indexes which have been deleted or which have never
been assigned values.
Here is the MDN documentation on that.
The find functionality works like this.
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) return false;
}
return (element > 1);
}
console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5
You can use this in ECMAScript 5 and below by defining the function.
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
enumerable: false,
configurable: true,
writable: true,
value: function(predicate) {
if (this == null) {
throw new TypeError('Array.prototype.find called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
if (i in list) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return value;
}
}
}
return undefined;
}
});
}
While array.indexOf(x)!=-1 is the most concise way to do this (and has been supported by non-Internet Explorer browsers for over decade...), it is not O(1), but rather O(N), which is terrible. If your array will not be changing, you can convert your array to a hashtable, then do table[x]!==undefined or ===undefined:
Array.prototype.toTable = function() {
var t = {};
this.forEach(function(x){t[x]=true});
return t;
}
Demo:
var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})
(Unfortunately, while you can create an Array.prototype.contains to "freeze" an array and store a hashtable in this._cache in two lines, this would give wrong results if you chose to edit your array later. JavaScript has insufficient hooks to let you keep this state, unlike Python for example.)
One can use Set that has the method "has()":
function contains(arr, obj) {
var proxy = new Set(arr);
if (proxy.has(obj))
return true;
else
return false;
}
var arr = ['Happy', 'New', 'Year'];
console.log(contains(arr, 'Happy'));
Use:
var myArray = ['yellow', 'orange', 'red'] ;
alert(!!~myArray.indexOf('red')); //true
Demo
To know exactly what the tilde ~ do at this point, refer to this question What does a tilde do when it precedes an expression?.
OK, you can just optimise your code to get the result!
There are many ways to do this which are cleaner and better, but I just wanted to get your pattern and apply to that using JSON.stringify, just simply do something like this in your case:
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (JSON.stringify(a[i]) === JSON.stringify(obj)) {
return true;
}
}
return false;
}
Surprised that this question still doesn't have latest syntax added, adding my 2 cents.
Let's say we have array of Objects arrObj and we want to search obj in it.
Array.prototype.indexOf -> (returns index or -1) is generally used for finding index of element in array.
This can also be used for searching object but only works if you are passing reference to same object.
let obj = { name: 'Sumer', age: 36 };
let arrObj = [obj, { name: 'Kishor', age: 46 }, { name: 'Rupen', age: 26 }];
console.log(arrObj.indexOf(obj));// 0
console.log(arrObj.indexOf({ name: 'Sumer', age: 36 })); //-1
console.log([1, 3, 5, 2].indexOf(2)); //3
Array.prototype.includes -> (returns true or false)
console.log(arrObj.includes(obj)); //true
console.log(arrObj.includes({ name: 'Sumer', age: 36 })); //false
console.log([1, 3, 5, 2].includes(2)); //true
Array.prototype.find -> (takes callback, returns first value/object that returns true in CB).
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }
console.log([1, 3, 5, 2].find(e => e > 2)); //3
Array.prototype.findIndex -> (takes callback, returns index of first value/object that returns true in CB).
console.log(arrObj.findIndex(e => e.age > 40)); //1
console.log(arrObj.findIndex(e => e.age > 40)); //1
console.log([1, 3, 5, 2].findIndex(e => e > 2)); //1
Since find and findIndex takes a callback, we can be fetch any object(even if we don't have the reference) from array by creatively setting the true condition.
It has one parameter: an array numbers of objects. Each object in the array has two integer properties denoted by x and y. The function must return a count of all such objects in the array that satisfy numbers.x == numbers.y
var numbers = [ { x: 1, y: 1 },
{ x: 2, y: 3 },
{ x: 3, y: 3 },
{ x: 3, y: 4 },
{ x: 4, y: 5 } ];
var count = 0;
var n = numbers.length;
for (var i =0;i<n;i++)
{
if(numbers[i].x==numbers[i].y)
{count+=1;}
}
alert(count);
Related
What is the most concise and efficient way to find out if a JavaScript array contains a value?
This is the only way I know to do it:
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Is there a better and more concise way to accomplish this?
This is very closely related to Stack Overflow question Best way to find an item in a JavaScript Array? which addresses finding objects in an array using indexOf.
Modern browsers have Array#includes, which does exactly that and is widely supported by everyone except IE:
console.log(['joe', 'jane', 'mary'].includes('jane')); //true
You can also use Array#indexOf, which is less direct, but doesn't require polyfills for outdated browsers.
console.log(['joe', 'jane', 'mary'].indexOf('jane') >= 0); //true
Many frameworks also offer similar methods:
jQuery: $.inArray(value, array, [fromIndex])
Underscore.js: _.contains(array, value) (also aliased as _.include and _.includes)
Dojo Toolkit: dojo.indexOf(array, value, [fromIndex, findLast])
Prototype: array.indexOf(value)
MooTools: array.indexOf(value)
MochiKit: findValue(array, value)
MS Ajax: array.indexOf(value)
Ext: Ext.Array.contains(array, value)
Lodash: _.includes(array, value, [from]) (is _.contains prior 4.0.0)
Ramda: R.includes(value, array)
Notice that some frameworks implement this as a function, while others add the function to the array prototype.
Update from 2019: This answer is from 2008 (11 years old!) and is not relevant for modern JS usage. The promised performance improvement was based on a benchmark done in browsers of that time. It might not be relevant to modern JS execution contexts. If you need an easy solution, look for other answers. If you need the best performance, benchmark for yourself in the relevant execution environments.
As others have said, the iteration through the array is probably the best way, but it has been proven that a decreasing while loop is the fastest way to iterate in JavaScript. So you may want to rewrite your code as follows:
function contains(a, obj) {
var i = a.length;
while (i--) {
if (a[i] === obj) {
return true;
}
}
return false;
}
Of course, you may as well extend Array prototype:
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
}
return false;
}
And now you can simply use the following:
alert([1, 2, 3].contains(2)); // => true
alert([1, 2, 3].contains('2')); // => false
indexOf maybe, but it's a "JavaScript extension to the ECMA-262 standard; as such it may not be present in other implementations of the standard."
Example:
[1, 2, 3].indexOf(1) => 0
["foo", "bar", "baz"].indexOf("bar") => 1
[1, 2, 3].indexOf(4) => -1
AFAICS Microsoft does not offer some kind of alternative to this, but you can add similar functionality to arrays in Internet Explorer (and other browsers that don't support indexOf) if you want to, as a quick Google search reveals (for example, this one).
The top answers assume primitive types but if you want to find out if an array contains an object with some trait, Array.prototype.some() is an elegant solution:
const items = [ {a: '1'}, {a: '2'}, {a: '3'} ]
items.some(item => item.a === '3') // returns true
items.some(item => item.a === '4') // returns false
The nice thing about it is that the iteration is aborted once the element is found so unnecessary iteration cycles are spared.
Also, it fits nicely in an if statement since it returns a boolean:
if (items.some(item => item.a === '3')) {
// do something
}
* As jamess pointed out in the comment, at the time of this answer, September 2018, Array.prototype.some() is fully supported: caniuse.com support table
ECMAScript 7 introduces Array.prototype.includes.
It can be used like this:
[1, 2, 3].includes(2); // true
[1, 2, 3].includes(4); // false
It also accepts an optional second argument fromIndex:
[1, 2, 3].includes(3, 3); // false
[1, 2, 3].includes(3, -1); // true
Unlike indexOf, which uses Strict Equality Comparison, includes compares using SameValueZero equality algorithm. That means that you can detect if an array includes a NaN:
[1, 2, NaN].includes(NaN); // true
Also unlike indexOf, includes does not skip missing indices:
new Array(5).includes(undefined); // true
It can be polyfilled to make it work on all browsers.
Let's say you've defined an array like so:
const array = [1, 2, 3, 4]
Below are three ways of checking whether there is a 3 in there. All of them return either true or false.
Native Array method (since ES2016) (compatibility table)
array.includes(3) // true
As custom Array method (pre ES2016)
// Prefixing the method with '_' to avoid name clashes
Object.defineProperty(Array.prototype, '_includes', { value: function (v) { return this.indexOf(v) !== -1 }})
array._includes(3) // true
Simple function
const includes = (a, v) => a.indexOf(v) !== -1
includes(array, 3) // true
Here's a JavaScript 1.6 compatible implementation of Array.indexOf:
if (!Array.indexOf) {
Array.indexOf = [].indexOf ?
function(arr, obj, from) {
return arr.indexOf(obj, from);
} :
function(arr, obj, from) { // (for IE6)
var l = arr.length,
i = from ? parseInt((1 * from) + (from < 0 ? l : 0), 10) : 0;
i = i < 0 ? 0 : i;
for (; i < l; i++) {
if (i in arr && arr[i] === obj) {
return i;
}
}
return -1;
};
}
Use:
function isInArray(array, search)
{
return array.indexOf(search) >= 0;
}
// Usage
if(isInArray(my_array, "my_value"))
{
//...
}
Extending the JavaScript Array object is a really bad idea because you introduce new properties (your custom methods) into for-in loops which can break existing scripts. A few years ago the authors of the Prototype library had to re-engineer their library implementation to remove just this kind of thing.
If you don't need to worry about compatibility with other JavaScript running on your page, go for it, otherwise, I'd recommend the more awkward, but safer free-standing function solution.
Performance
Today 2020.01.07 I perform tests on MacOs HighSierra 10.13.6 on Chrome v78.0.0, Safari v13.0.4 and Firefox v71.0.0 for 15 chosen solutions. Conclusions
solutions based on JSON, Set and surprisingly find (K,N,O) are slowest on all browsers
the es6 includes (F) is fast only on chrome
the solutions based on for (C,D) and indexOf (G,H) are quite-fast on all browsers on small and big arrays so probably they are best choice for efficient solution
the solutions where index decrease during loop, (B) is slower probably because the way of CPU cache works.
I also run test for big array when searched element was on position 66% of array length, and solutions based on for (C,D,E) gives similar results (~630 ops/sec - but the E on safari and firefox was 10-20% slower than C and D)
Results
Details
I perform 2 tests cases: for array with 10 elements, and array with 1 milion elements. In both cases we put searched element in the array middle.
let log = (name,f) => console.log(`${name}: 3-${f(arr,'s10')} 's7'-${f(arr,'s7')} 6-${f(arr,6)} 's3'-${f(arr,'s3')}`)
let arr = [1,2,3,4,5,'s6','s7','s8','s9','s10'];
//arr = new Array(1000000).fill(123); arr[500000]=7;
function A(a, val) {
var i = -1;
var n = a.length;
while (i++<n) {
if (a[i] === val) {
return true;
}
}
return false;
}
function B(a, val) {
var i = a.length;
while (i--) {
if (a[i] === val) {
return true;
}
}
return false;
}
function C(a, val) {
for (var i = 0; i < a.length; i++) {
if (a[i] === val) return true;
}
return false;
}
function D(a,val)
{
var len = a.length;
for(var i = 0 ; i < len;i++)
{
if(a[i] === val) return true;
}
return false;
}
function E(a, val){
var n = a.length-1;
var t = n/2;
for (var i = 0; i <= t; i++) {
if (a[i] === val || a[n-i] === val) return true;
}
return false;
}
function F(a,val) {
return a.includes(val);
}
function G(a,val) {
return a.indexOf(val)>=0;
}
function H(a,val) {
return !!~a.indexOf(val);
}
function I(a, val) {
return a.findIndex(x=> x==val)>=0;
}
function J(a,val) {
return a.some(x=> x===val);
}
function K(a, val) {
const s = JSON.stringify(val);
return a.some(x => JSON.stringify(x) === s);
}
function L(a,val) {
return !a.every(x=> x!==val);
}
function M(a, val) {
return !!a.find(x=> x==val);
}
function N(a,val) {
return a.filter(x=>x===val).length > 0;
}
function O(a, val) {
return new Set(a).has(val);
}
log('A',A);
log('B',B);
log('C',C);
log('D',D);
log('E',E);
log('F',F);
log('G',G);
log('H',H);
log('I',I);
log('J',J);
log('K',K);
log('L',L);
log('M',M);
log('N',N);
log('O',O);
This shippet only presents functions used in performance tests - it not perform tests itself!
Array small - 10 elements
You can perform tests in your machine HERE
Array big - 1.000.000 elements
You can perform tests in your machine HERE
One-liner:
function contains(arr, x) {
return arr.filter(function(elem) { return elem == x }).length > 0;
}
Thinking out of the box for a second, if you are making this call many many times, it is vastly more efficient to use an associative array a Map to do lookups using a hash function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
I use the following:
Array.prototype.contains = function (v) {
return this.indexOf(v) > -1;
}
var a = [ 'foo', 'bar' ];
a.contains('foo'); // true
a.contains('fox'); // false
function contains(a, obj) {
return a.some(function(element){return element == obj;})
}
Array.prototype.some() was added to the ECMA-262 standard in the 5th edition
If you are using JavaScript 1.6 or later (Firefox 1.5 or later) you can use Array.indexOf. Otherwise, I think you are going to end up with something similar to your original code.
A hopefully faster bidirectional indexOf / lastIndexOf alternative
2015
While the new method includes is very nice, the support is basically zero for now.
It's a long time that I was thinking of a way to replace the slow indexOf/lastIndexOf functions.
A performant way has already been found, looking at the top answers. From those I chose the contains function posted by #Damir Zekic which should be the fastest one. But it also states that the benchmarks are from 2008 and so are outdated.
I also prefer while over for, but for not a specific reason I ended writing the function with a for loop. It could be also done with a while --.
I was curious if the iteration was much slower if I check both sides of the array while doing it. Apparently no, and so this function is around two times faster than the top voted ones. Obviously it's also faster than the native one. This is in a real world environment, where you never know if the value you are searching is at the beginning or at the end of the array.
When you know you just pushed an array with a value, using lastIndexOf remains probably the best solution, but if you have to travel through big arrays and the result could be everywhere, this could be a solid solution to make things faster.
Bidirectional indexOf/lastIndexOf
function bidirectionalIndexOf(a, b, c, d, e){
for(c=a.length,d=c*1; c--; ){
if(a[c]==b) return c; //or this[c]===b
if(a[e=d-1-c]==b) return e; //or a[e=d-1-c]===b
}
return -1
}
//Usage
bidirectionalIndexOf(array,'value');
Performance test
https://jsbench.me/7el1b8dj80
As a test I created an array with 100k entries.
Three queries: at the beginning, in the middle & at the end of the array.
I hope you also find this interesting and test the performance.
Note: As you can see I slightly modified the contains function to reflect the indexOf & lastIndexOf output (so basically true with the index and false with -1). That shouldn't harm it.
The array prototype variant
Object.defineProperty(Array.prototype,'bidirectionalIndexOf',{value:function(b,c,d,e){
for(c=this.length,d=c*1; c--; ){
if(this[c]==b) return c; //or this[c]===b
if(this[e=d-1-c] == b) return e; //or this[e=d-1-c]===b
}
return -1
},writable:false, enumerable:false});
// Usage
array.bidirectionalIndexOf('value');
The function can also be easily modified to return true or false or even the object, string or whatever it is.
And here is the while variant:
function bidirectionalIndexOf(a, b, c, d){
c=a.length; d=c-1;
while(c--){
if(b===a[c]) return c;
if(b===a[d-c]) return d-c;
}
return c
}
// Usage
bidirectionalIndexOf(array,'value');
How is this possible?
I think that the simple calculation to get the reflected index in an array is so simple that it's two times faster than doing an actual loop iteration.
Here is a complex example doing three checks per iteration, but this is only possible with a longer calculation which causes the slowdown of the code.
https://web.archive.org/web/20151019160219/http://jsperf.com/bidirectionalindexof/2
function inArray(elem,array)
{
var len = array.length;
for(var i = 0 ; i < len;i++)
{
if(array[i] == elem){return i;}
}
return -1;
}
Returns array index if found, or -1 if not found
If you are checking repeatedly for existence of an object in an array you should maybe look into
Keeping the array sorted at all times by doing insertion sort in your array (put new objects in on the right place)
Make updating objects as remove+sorted insert operation and
Use a binary search lookup in your contains(a, obj).
We use this snippet (works with objects, arrays, strings):
/*
* #function
* #name Object.prototype.inArray
* #description Extend Object prototype within inArray function
*
* #param {mix} needle - Search-able needle
* #param {bool} searchInKey - Search needle in keys?
*
*/
Object.defineProperty(Object.prototype, 'inArray',{
value: function(needle, searchInKey){
var object = this;
if( Object.prototype.toString.call(needle) === '[object Object]' ||
Object.prototype.toString.call(needle) === '[object Array]'){
needle = JSON.stringify(needle);
}
return Object.keys(object).some(function(key){
var value = object[key];
if( Object.prototype.toString.call(value) === '[object Object]' ||
Object.prototype.toString.call(value) === '[object Array]'){
value = JSON.stringify(value);
}
if(searchInKey){
if(value === needle || key === needle){
return true;
}
}else{
if(value === needle){
return true;
}
}
});
},
writable: true,
configurable: true,
enumerable: false
});
Usage:
var a = {one: "first", two: "second", foo: {three: "third"}};
a.inArray("first"); //true
a.inArray("foo"); //false
a.inArray("foo", true); //true - search by keys
a.inArray({three: "third"}); //true
var b = ["one", "two", "three", "four", {foo: 'val'}];
b.inArray("one"); //true
b.inArray('foo'); //false
b.inArray({foo: 'val'}) //true
b.inArray("{foo: 'val'}") //false
var c = "String";
c.inArray("S"); //true
c.inArray("s"); //false
c.inArray("2", true); //true
c.inArray("20", true); //false
Solution that works in all modern browsers:
function contains(arr, obj) {
const stringifiedObj = JSON.stringify(obj); // Cache our object to not call `JSON.stringify` on every iteration
return arr.some(item => JSON.stringify(item) === stringifiedObj);
}
Usage:
contains([{a: 1}, {a: 2}], {a: 1}); // true
IE6+ solution:
function contains(arr, obj) {
var stringifiedObj = JSON.stringify(obj)
return arr.some(function (item) {
return JSON.stringify(item) === stringifiedObj;
});
}
// .some polyfill, not needed for IE9+
if (!('some' in Array.prototype)) {
Array.prototype.some = function (tester, that /*opt*/) {
for (var i = 0, n = this.length; i < n; i++) {
if (i in this && tester.call(that, this[i], i, this)) return true;
} return false;
};
}
Usage:
contains([{a: 1}, {a: 2}], {a: 1}); // true
Why to use JSON.stringify?
Array.indexOf and Array.includes (as well as most of the answers here) only compare by reference and not by value.
[{a: 1}, {a: 2}].includes({a: 1});
// false, because {a: 1} is a new object
Bonus
Non-optimized ES6 one-liner:
[{a: 1}, {a: 2}].some(item => JSON.stringify(item) === JSON.stringify({a: 1));
// true
Note:
Comparing objects by value will work better if the keys are in the same order, so to be safe you might sort the keys first with a package like this one: https://www.npmjs.com/package/sort-keys
Updated the contains function with a perf optimization. Thanks itinance for pointing it out.
There are a couple of method which makes this easy to achieve (includes, some, find, findIndex)
const array = [1, 2, 3, 4, 5, 6, 7];
console.log(array.includes(3));
//includes() determines whether an array includes a certain value among its entries
console.log(array.some(x => x === 3));
//some() tests if at least one element in the array passes the test implemented by the provided function
console.log(array.find(x => x === 3) ? true : false);
//find() returns the value of the first element in the provided array that satisfies the provided testing function
console.log(array.findIndex(x => x === 3) > -1);
//findIndex() returns the index of the first element in the array that satisfies the provided testing function, else returning -1.
More about includes, some, find, findIndex
Use lodash's some function.
It's concise, accurate and has great cross platform support.
The accepted answer does not even meet the requirements.
Requirements: Recommend most concise and efficient way to find out if a JavaScript array contains an object.
Accepted Answer:
$.inArray({'b': 2}, [{'a': 1}, {'b': 2}])
> -1
My recommendation:
_.some([{'a': 1}, {'b': 2}], {'b': 2})
> true
Notes:
$.inArray works fine for determining whether a scalar value exists in an array of scalars...
$.inArray(2, [1,2])
> 1
... but the question clearly asks for an efficient way to determine if an object is contained in an array.
In order to handle both scalars and objects, you could do this:
(_.isObject(item)) ? _.some(ary, item) : (_.indexOf(ary, item) > -1)
Simple solution for this requirement is using find()
If you're having array of objects like below,
var users = [{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "admin"},
{id: "105", name: "user"}];
Then you can check whether the object with your value is already present or not:
let data = users.find(object => object['id'] === '104');
if data is null then no admin, else it will return the existing object like:
{id: "104", name: "admin"}
Then you can find the index of that object in the array and replace the object using the code:
let indexToUpdate = users.indexOf(data);
let newObject = {id: "104", name: "customer"};
users[indexToUpdate] = newObject;//your new object
console.log(users);
you will get value like:
[{id: "101", name: "Choose one..."},
{id: "102", name: "shilpa"},
{id: "103", name: "anita"},
{id: "104", name: "customer"},
{id: "105", name: "user"}];
ECMAScript 6 has an elegant proposal on find.
The find method executes the callback function once for each element
present in the array until it finds one where callback returns a true
value. If such an element is found, find immediately returns the value
of that element. Otherwise, find returns undefined. callback is
invoked only for indexes of the array which have assigned values; it
is not invoked for indexes which have been deleted or which have never
been assigned values.
Here is the MDN documentation on that.
The find functionality works like this.
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) return false;
}
return (element > 1);
}
console.log( [4, 6, 8, 12].find(isPrime) ); // Undefined, not found
console.log( [4, 5, 8, 12].find(isPrime) ); // 5
You can use this in ECMAScript 5 and below by defining the function.
if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', {
enumerable: false,
configurable: true,
writable: true,
value: function(predicate) {
if (this == null) {
throw new TypeError('Array.prototype.find called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0;
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) {
if (i in list) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) {
return value;
}
}
}
return undefined;
}
});
}
While array.indexOf(x)!=-1 is the most concise way to do this (and has been supported by non-Internet Explorer browsers for over decade...), it is not O(1), but rather O(N), which is terrible. If your array will not be changing, you can convert your array to a hashtable, then do table[x]!==undefined or ===undefined:
Array.prototype.toTable = function() {
var t = {};
this.forEach(function(x){t[x]=true});
return t;
}
Demo:
var toRemove = [2,4].toTable();
[1,2,3,4,5].filter(function(x){return toRemove[x]===undefined})
(Unfortunately, while you can create an Array.prototype.contains to "freeze" an array and store a hashtable in this._cache in two lines, this would give wrong results if you chose to edit your array later. JavaScript has insufficient hooks to let you keep this state, unlike Python for example.)
One can use Set that has the method "has()":
function contains(arr, obj) {
var proxy = new Set(arr);
if (proxy.has(obj))
return true;
else
return false;
}
var arr = ['Happy', 'New', 'Year'];
console.log(contains(arr, 'Happy'));
Use:
var myArray = ['yellow', 'orange', 'red'] ;
alert(!!~myArray.indexOf('red')); //true
Demo
To know exactly what the tilde ~ do at this point, refer to this question What does a tilde do when it precedes an expression?.
OK, you can just optimise your code to get the result!
There are many ways to do this which are cleaner and better, but I just wanted to get your pattern and apply to that using JSON.stringify, just simply do something like this in your case:
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (JSON.stringify(a[i]) === JSON.stringify(obj)) {
return true;
}
}
return false;
}
Surprised that this question still doesn't have latest syntax added, adding my 2 cents.
Let's say we have array of Objects arrObj and we want to search obj in it.
Array.prototype.indexOf -> (returns index or -1) is generally used for finding index of element in array.
This can also be used for searching object but only works if you are passing reference to same object.
let obj = { name: 'Sumer', age: 36 };
let arrObj = [obj, { name: 'Kishor', age: 46 }, { name: 'Rupen', age: 26 }];
console.log(arrObj.indexOf(obj));// 0
console.log(arrObj.indexOf({ name: 'Sumer', age: 36 })); //-1
console.log([1, 3, 5, 2].indexOf(2)); //3
Array.prototype.includes -> (returns true or false)
console.log(arrObj.includes(obj)); //true
console.log(arrObj.includes({ name: 'Sumer', age: 36 })); //false
console.log([1, 3, 5, 2].includes(2)); //true
Array.prototype.find -> (takes callback, returns first value/object that returns true in CB).
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }
console.log(arrObj.find(e => e.age > 40)); //{ name: 'Kishor', age: 46 }
console.log([1, 3, 5, 2].find(e => e > 2)); //3
Array.prototype.findIndex -> (takes callback, returns index of first value/object that returns true in CB).
console.log(arrObj.findIndex(e => e.age > 40)); //1
console.log(arrObj.findIndex(e => e.age > 40)); //1
console.log([1, 3, 5, 2].findIndex(e => e > 2)); //1
Since find and findIndex takes a callback, we can be fetch any object(even if we don't have the reference) from array by creatively setting the true condition.
It has one parameter: an array numbers of objects. Each object in the array has two integer properties denoted by x and y. The function must return a count of all such objects in the array that satisfy numbers.x == numbers.y
var numbers = [ { x: 1, y: 1 },
{ x: 2, y: 3 },
{ x: 3, y: 3 },
{ x: 3, y: 4 },
{ x: 4, y: 5 } ];
var count = 0;
var n = numbers.length;
for (var i =0;i<n;i++)
{
if(numbers[i].x==numbers[i].y)
{count+=1;}
}
alert(count);
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?
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).
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
}
Another solution is to create a lookup object:
var lookup = {};
for (var i = 0, len = array.length; i < len; i++) {
lookup[array[i].id] = array[i];
}
... now you can use lookup[id]...
This is especially interesting if you need to do many lookups.
This won't need much more memory since the IDs and objects will be shared.
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.
Underscore.js has a nice method for that:
myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })
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
Try the following
function findById(source, id) {
for (var i = 0; i < source.length; i++) {
if (source[i].id === id) {
return source[i];
}
}
throw "Couldn't find object with id: " + id;
}
myArray.filter(function(a){ return a.id == some_id_you_want })[0]
A generic and more flexible version of the findById function above:
// array = [{key:value},{key:value}]
function objectFindByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
var array = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var result_obj = objectFindByKey(array, 'id', '45');
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
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)
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
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
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
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/
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
You can use filters,
function getById(id, myArray) {
return myArray.filter(function(obj) {
if(obj.id == id) {
return obj
}
})[0]
}
get_my_obj = getById(73, myArray);
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
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/
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];
}
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...
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;
});
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'
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.
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
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
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;
});
}
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");
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
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.
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.
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
Is there a way to loop backwards through an array using forEach (not any other kind of loop, I know how to do with with a for / standard ways) and without actually reversing the array itself?
let arr = [1, 2, 3];
arr.slice().reverse().forEach(x => console.log(x))
will print:
3
2
1
arr will still be [1, 2, 3], the .slice() creates a shallow copy.
There is a similar array method that has a reverse counter part, reduce comes together with reduceRight:
const array = ['alpha', 'beta', 'gamma'];
array.reduceRight((_, elem) => console.log(elem), null);
When using it for the requested purpose, make sure to provide a second argument. It can be null or anything else. Also note that the callback function has as first argument the accumulator, which you don't need for this purpose.
If including a library is an option:
Lodash: forEachRight.
Just use a for loop. Start at the end of the array and go backwards from there.
const array = ['blastoff', 1, 2, 3];
for (let index = array.length - 1; index >= 0; index--) {
const element = array[index];
console.log(element);
}
No, forEach only processes forward through the array. So you'd have to do something else, which you've said in your question was out of scope.
I can think of two options which just use precursors to using forEach (so, they don't use a for loop or other kind of loop). I don't know if those would be out of scope or not, so here they are:
Copy the array and reverse the copy, then use forEach on it
Use Object.keys to get the indexes, reverse that, then use forEach on it (which will loop through the indexes, not the values, but then we can look them up)
Here's #1:
slice copies the array (shallow copy, so not likely to be expensive), then we reverse it, then forEach:
var a = ['one', 'two', 'three'];
a.slice().reverse().forEach(function(entry) {
console.log(entry);
});
console.log("Proof that a is not, itself, reversed: " +
JSON.stringify(a));
Here's #2:
We use Object.keys to get the array indices (using filter if you store non-element properties in your arrays), reverse that, and then loop through the result:
var a = ['one', 'two', 'three'];
Object.keys(a).reverse().forEach(function(index) {
console.log(a[index]);
});
console.log("Proof that a is not, itself, reversed: " +
JSON.stringify(a));
Side note: Here's what I mean about using filter if you have non-element properties on your array:
var a = ['one', 'two', 'three'];
a.nonElementProperty = "foo";
Object.keys(a).filter(function(name) {
return String(+name) === name;
}).reverse().forEach(function(index) {
console.log(a[index]);
});
console.log("Proof that a is not, itself, reversed: " +
JSON.stringify(a));
As yet the browsers do not seem to have optimised the Array.forEach function. With not much effort you can write a simple polyfill that out performs the Array.forEach method by at least 10 to 1.
So you can create your own Array.revEach and have it outperform the native Array.forEach, thought I hope that the browsers address the very slow performance of Array.forEach soon and make the need to polyfill actual existing methods not necessary.
For Array.revEach out performs Array.forEach running 17 times faster on "Chrome 46.0.2490.22 beta-m"
if (Array.prototype.revEach === undefined) {
Object.defineProperty(Array.prototype, 'revEach', {
writable : false,
enumerable : false,
configurable : false,
value : function (func) {
var i;
var len = this.length-1;
for (i = len; i >= 0; i--) {
func(this[i], i, this);
}
}
});
}
Just to add the actual official polyfill modified to reverse. Comments show my changes.
// Production steps of ECMA-262, Edition 5, 15.4.4.18
// Reference: http://es5.github.io/#x15.4.4.18
// Modified by Blindman67 to revEach
if (!Array.prototype.revEach) { // name changed
Array.prototype.revEach = function(callback, thisArg) { // name changed
var T; // k defined where len was
if (this == null) {
throw new TypeError(' this is null or not defined');
}
var O = Object(this);
var k = (O.length >>> 0)-1; // set k (counter) ToUint32
// len var removed
if (typeof callback !== "function") {
throw new TypeError(callback + ' is not a function');
}
if (arguments.length > 1) {
T = thisArg;
}
while (k >= 0) { // reverse condition
var kValue;
if (k in O) {
kValue = O[k];
callback.call(T, kValue, k, O);
}
k--; // dec counter
}
};
}
array.forEach has 3 parameters. You can use these to effectively forEach backward.
var arr = [1, 2, 3];
arr.forEach(function(x, index, the_array) {
let x_prime = the_array[the_array.length-1-index]
console.log(x_prime);
})
will print
3
2
1
This can be accomplished relatively concisely using the reverse method, the forEach method, and (if using ES6) the arrow function
var someArray = ["a","b","c","d"];
someArray.reverse().forEach(arrayItem =>
console.log(arrayItem)
)
If you are not using ES6, the solution is about the same, just without the arrow function.
var someArray = ["a","b","c","d"];
someArray.reverse().forEach(function(arrayItem) {
console.log(arrayItem)
})
Both will print to the console:
d
c
b
a
There are many ways to achive this task.
Firsly we can use Array.reduceRight() method
[1,2,3,4,5].reduceRight((total,item) => {
console.log(item);
// Do somthing here and remember the return statement
return item;
},0)
Output: 5,4,3,2,1
the reduceRight method traverse an array in right to left manner and we can get advantage of it.
,but always keep in mind that you have to return something to keep going this loop until the length is reached.
As a second method we can use Array.reverse()
this method first format the array in reversed manner then returns it, and now you can iterate in reverse manner.
[1,2,3].reverse().map(n => console.log(n));
Output: 3,2,1
But the disadvantage of this method is that if you have thousands of entries in array then it may affect your performance.
Third and the most easiest way it to use classical for loop
let array = [1,2,3,4,5];
let start = array.length;
for(;start >= 0;start--){
// travese in right to left manner
console.log(array[start])
}
What about:
const array = [1, 2, 3];
const revArray = [...array].reverse() // won't affect the original array
revArray.forEach(x => console.log(x)) // 3, 2, 1
One liner:
[...array].reverse().forEach(x => console.log(x)) // 3, 2, 1
With index var:
[...array].reverse().forEach((val, index) => {
const revIndex = array.length - i - 1
console.log(revIndex) // 0, 1, 2
console.log(revIndex) // 2, 1, 0
console.log(val) // 3, 2, 1
})
You can also do it this way
let arr = [1, 3, 5, 7, 9];
arr.forEach(value => {
console.log(value);
})
let reversed = new Array(arr.reverse());
console.log("\n\nReversed: ");
reversed.forEach(value => {
value.forEach(val => {
console.log(val)
})
})
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?
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).
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
}
Another solution is to create a lookup object:
var lookup = {};
for (var i = 0, len = array.length; i < len; i++) {
lookup[array[i].id] = array[i];
}
... now you can use lookup[id]...
This is especially interesting if you need to do many lookups.
This won't need much more memory since the IDs and objects will be shared.
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.
Underscore.js has a nice method for that:
myArray = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'},etc.]
obj = _.find(myArray, function(obj) { return obj.id == '45' })
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
Try the following
function findById(source, id) {
for (var i = 0; i < source.length; i++) {
if (source[i].id === id) {
return source[i];
}
}
throw "Couldn't find object with id: " + id;
}
myArray.filter(function(a){ return a.id == some_id_you_want })[0]
A generic and more flexible version of the findById function above:
// array = [{key:value},{key:value}]
function objectFindByKey(array, key, value) {
for (var i = 0; i < array.length; i++) {
if (array[i][key] === value) {
return array[i];
}
}
return null;
}
var array = [{'id':'73','foo':'bar'},{'id':'45','foo':'bar'}];
var result_obj = objectFindByKey(array, 'id', '45');
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
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)
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
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
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
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/
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
You can use filters,
function getById(id, myArray) {
return myArray.filter(function(obj) {
if(obj.id == id) {
return obj
}
})[0]
}
get_my_obj = getById(73, myArray);
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
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/
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];
}
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...
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;
});
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'
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.
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
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
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;
});
}
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");
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
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.
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.
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
I have a JSON webservice in the following format.
{ Name:['a','b'], Name:['cd','ef'], Age:{...}, Address:{...} }.
Here I have 2 arrays & 2 objects inside an object and these (array & objects) numbers may vary. What I need is, how can I get the number of Arrays alone from the main Object? There may exist another way to solve my problem but I need my code to be in a .JS (javascript file).
When I tried:
Object.keys(mainobject).length;
It gives total count of array + objects in main object.
var data = { Name:['a','b'], OtherName:['cd','ef'], Age:{a: 12}, Address:{a: 'asdf'} }
var numberOfArrays = Object.keys(data).filter(function(key) {
return data[key] instanceof Array; //or Array.isArray(data[key]) if the array was created in another frame
}).length;
alert(numberOfArrays);
Note: This won't work in older versions of IE
jsFiddle
To make it work with browsers that don't support it, use the shims from MDN:
Object.keys
Array.filter
I'd write something to count all the types
var obj = {
k1: ['a','b'], k2: ['cd','ef'],
k3: 0, k4: 1,
k5: {a:'b'},
k6: new Date(),
k7: "foo"
};
function getType(obj) {
var type = Object.prototype.toString.call(obj).slice(8, -1);
if (type === 'Object') return obj.constructor.name;
return type;
}
function countTypes(obj) {
var k, hop = Object.prototype.hasOwnProperty,
ret = {}, type;
for (k in obj) if (hop.call(obj, k)) {
type = getType(obj[k]);
if (!ret[type]) ret[type] = 1;
else ++ret[type];
}
return ret;
}
var theTypes = countTypes(obj);
// Object {Array: 2, Number: 2, Object: 1, Date: 1, String: 1}
Now if I wanted to know the number of Arrays only
var numArrays = theTypes.Array || 0; // 2 Arrays in this example
You could try checking the type of each member of your object.
var count = 0;
for (var foo in mainobject) {
if (foo instanceof Array) count++;
}
Now all you have to do is read the value of count.