263

I need to determine if an object already exists in an array in javascript.

eg (dummycode):

var carBrands = [];

var car1 = {name:'ford'};
var car2 = {name:'lexus'};
var car3 = {name:'maserati'};
var car4 = {name:'ford'};

carBrands.push(car1);
carBrands.push(car2);
carBrands.push(car3);
carBrands.push(car4);

now the "carBrands" array contains all instances. I'm now looking a fast solution to check if an instance of car1, car2, car3 or car4 is already in the carBrands array.

eg:

var contains =  carBrands.Contains(car1); //<--- returns bool.

car1 and car4 contain the same data but are different instances they should be tested as not equal.

Do I have add something like a hash to the objects on creation? Or is there a faster way to do this in Javascript.

I am looking for the fastest solution here, if dirty, so it has to be ;) In my app it has to deal with around 10000 instances.

no jquery

Caspar Kleijne
  • 21,552
  • 13
  • 72
  • 102
  • Are you going to be checking based on dictionaries, or do you want to test using names? You could using a hash for `carBrands`, and then just testing on the keys you want. – girasquid Jan 03 '11 at 18:23
  • 2
    you can use the method some: let contains = carsBrands.some( car => car.name == car1.name) – jc.vargas.valencia Oct 30 '19 at 16:08
  • 7
    This question is different from the duplicate because it deals with objects rather than primitives. Using a simple `===` will only work in the simplest case where you have exact references to the objects in the array. – Heretic Monkey Aug 06 '20 at 15:56
  • The caveats of using [`includes`](//developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/includes) with objects have been addressed in [How do I check if an array includes a value in JavaScript?](/q/237104/4642212) multiple times. Some of the answers _here_ don’t even consider this caveat. I don’t see a reason why this shouldn’t be closed as a duplicate. It does more harm than good to separate these questions by use case and leave the object reference caveat entirely unaddressed by one question, just because it doesn’t explicitly ask about object references. – Sebastian Simon Jan 29 '23 at 11:25

18 Answers18

193

Use something like this:

function containsObject(obj, list) {
    var i;
    for (i = 0; i < list.length; i++) {
        if (list[i] === obj) {
            return true;
        }
    }

    return false;
}

In this case, containsObject(car4, carBrands) is true. Remove the carBrands.push(car4); call and it will return false instead. If you later expand to using objects to store these other car objects instead of using arrays, you could use something like this instead:

function containsObject(obj, list) {
    var x;
    for (x in list) {
        if (list.hasOwnProperty(x) && list[x] === obj) {
            return true;
        }
    }

    return false;
}

This approach will work for arrays too, but when used on arrays it will be a tad slower than the first option.

cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • +1. My answer was missing the point. This is the right one. (as a side note you can do exactly what the OP did extending Array.prototype) – Pablo Fernandez Jan 03 '11 at 18:30
  • Should add a var before the i or x, for example: for (var x in list) – Rob B Jul 17 '13 at 09:06
  • @RobB Yeah, looks like I made a copy-paste error -- `var i` should have been `var x`. Fixed, thanks for pointing that out. – cdhowie Jul 17 '13 at 17:05
  • 6
    it should be JSON.stringify(list[i]) === JSON.stringify(obj) and not list[i] === obj – moni sogani Feb 19 '18 at 13:44
  • @cdhowie What he said worked for me. It doesn't work if I do the list[i] === obj. You didn't even elaborate why. – Martín Nieva Dec 23 '19 at 18:26
  • 3
    @MartínNieva Probably because the object you're looking for isn't in the list, but rather a different object that compares as deeply-equal. In that case, using lodash's [`isEqual()`](https://lodash.com/docs/4.17.15#isEqual) would be preferable to abusing serialization. (In fact, using lodash, this whole solution becomes a one-liner, combining `_.some` and `_.isEqual`: `_.some(list, v => _.isEqual(v, o))`.) – cdhowie Dec 23 '19 at 18:34
  • 3
    can’t believe such a simple thing in Python could be such complex in js. – Jcyrss Mar 12 '20 at 12:37
  • @Jcyrss Python has its own requirement for dealing with this case. `someObject in someList` doesn't work either unless: (1) the same object is in the list, in which case it would be just as simple in JavaScript, or (2) the objects implement the `__eq__` method to test for value equality. The two languages are actually remarkably similar when it comes to searching a list for a particular object. – cdhowie Mar 13 '20 at 15:38
159

Why don't you use the indexOf method of javascript arrays?

Check this out: MDN indexOf Arrays

Simply do:

carBrands.indexOf(car1);

It will return you the index (position in the array) of car1. It will return -1 if car1 was not found in the array.

http://jsfiddle.net/Fraximus/r154cd9o

Edit: Note that in the question, the requirements are to check for the same object referenced in the array, and NOT a new object. Even if the new object is identical in content to the object in the array, it is still a different object. As mentioned in the comments, objects are passed by reference in JS and the same object can exist multiple times in multiple structures.
If you want to create a new object and check if the array contains objects identical to your new one, this answer won't work (Julien's fiddle below), if you want to check for that same object's existence in the array, then this answer will work. Check out the fiddles here and in the comments.

Frax
  • 3,075
  • 1
  • 23
  • 27
  • 149
    indexOf always return -1 when you try to find object in an array... Tiny example here : http://jsfiddle.net/7B7dQ/1/ – Julien Apr 01 '14 at 14:11
  • 98
    Why does this have 40 upvotes if it plainly doesn't work? – waterplea Jun 11 '15 at 15:04
  • 16
    Gents, in the question, the OP wanted something like `carBrands.Contains(car1)`. If you do carBrands.indexOf(car1), IT WORKS. Check this out: http://jsfiddle.net/Fraximus/r154cd9o/ – Frax Jun 17 '15 at 08:56
  • 14
    In Julien's fiddle, it won't work because it's a new object, even though they are identical. – Frax Jun 17 '15 at 08:57
  • 43
    Remember that objects in JS are passed by reference. This means that _two objects that have the same properties with the same values are not the same object_. It also means that _an object can actually exist in multiple arrays simultaneously_. Example: http://jsfiddle.net/7B7dQ/33/ – Alex Langberg Jul 22 '15 at 10:01
  • This does not work at all. You can't compare objects like that. `car1 === car4` is always going to be `false`. – Jake Wilson Dec 20 '17 at 04:15
  • THIS ANSWER IS TOTALLY INCORRECT. The indexOf() will always return -1 when comparing objects. – codeepic Feb 05 '18 at 17:06
  • To clarify, this will only work when working with arrays rather than objects. Like an array of numbers for example. – Ali Almoullim Feb 26 '18 at 12:24
  • This is a great example, just try catch for referenceError and then create it if needed, https://stackoverflow.com/questions/2412139/how-can-you-bubble-up-errors-so-they-can-be-caught-in-the-same-try-catch-block – hounded Feb 07 '20 at 22:03
  • This doesn't work for objects. Please delete this answer. – DileepNimantha Aug 26 '20 at 04:37
  • 2
    I don't understand why so many people say this answer needs to be deleted. It is a good, concise answer that answers OP's question, while Julien's example does not reflect what OP tries to do. @Frax raised good points. I suspect many people did not bother to actually look at the question – Zhe Sep 16 '20 at 16:16
  • 1
    difference explained: http://jsfiddle.net/c9jhLg0o/ this definitely works! it will *not* work in cases, where you try to compare *copied, or new objects*. in that case you want to know "does my array hold an object that has the same properties as my object". indexOf will return an index if you want to know wheather you already pushed an object into your array or not. great answer, for me at least. it looks for the reference in memory. – denns Jul 12 '21 at 12:40
46

Having been recently bitten by the FP bug reading many wonderful accounts of how neatly the functional paradigm fits with Javascript

I replicate the code for completeness sake and suggest two ways this can be done functionally.

    var carBrands = [];

  var car1 = {name:'ford'};
  var car2 = {name:'lexus'};
  var car3 = {name:'maserati'};
  var car4 = {name:'ford'};
  var car5 = {name:'toyota'};

  carBrands.push(car1);
  carBrands.push(car2);
  carBrands.push(car3);
  carBrands.push(car4);

  // ES6 approach which uses the includes method (Chrome47+, Firefox43+)

  carBrands.includes(car1) // -> true
  carBrands.includes(car5) // -> false

If you need to support older browsers use the polyfill, it seems IE9+ and Edge do NOT support it. Located in polyfill section of MSDN page

Alternatively I would like to propose an updated answer to cdhowie

// ES2015 syntax
function containsObject(obj, list) {

    return list.some(function(elem) {
      return elem === obj
    })
}

// or ES6+ syntax with cool fat arrows
function containsObject(obj, list) {

    return list.some(elem => elem === obj)
}
Community
  • 1
  • 1
Faktor 10
  • 1,868
  • 2
  • 21
  • 29
  • 2
    When I add `var car6 = {name:'ford'};` to your first solution and try `carBrands.includes(car6)`, it returns false. Can you explain this? – Prasanth Ganesan Feb 18 '19 at 13:30
  • 1
    @PrasanthGanesan the carBrands is an Array of objects, in this case with the shape of having a key of 'name' and a value of the type of car brand as a string. If you do not push your var car6 object into the array the include method will indeed return false, if you push it onto array it will return true. see my jsbin example - https://jsbin.com/xeluyizaze/edit?js,console – Faktor 10 Feb 18 '19 at 16:21
  • 3
    Same approach but actually comparing the objects: `arr.some((e) => Object.entries(e).toString() === Object.entries(obj).toString()) ` – Leon Vogler Jan 12 '22 at 10:13
21

try Array.prototype.some()

MDN Array.prototype.some


    function isBiggerThan10(element, index, array) {
      return element > 10;
    }
    [2, 5, 8, 1, 4].some(isBiggerThan10);  // false
    [12, 5, 8, 1, 4].some(isBiggerThan10); // true

UtillYou
  • 251
  • 2
  • 7
18

You could use jQuery's grep method:

$.grep(carBrands, function(obj) { return obj.name == "ford"; });

But as you specify no jQuery, you could just make a derivative of the function. From the source code:

function grepArray( elems, callback, inv ) {  
    var ret = [];  

    // Go through the array, only saving the items  
    // that pass the validator function  
    for ( var i = 0, length = elems.length; i < length; i++ ) {  
        if ( !inv !== !callback( elems[ i ], i ) ) {  
            ret.push( elems[ i ] );  
        }  
    }  

    return ret;  
}  

grepArray(carBrands, function(obj) { return obj.name == "ford"; });
leszek.hanusz
  • 5,152
  • 2
  • 38
  • 56
stef
  • 14,172
  • 2
  • 48
  • 70
12

I used underscore javascript library to tweak this issue.

function containsObject(obj, list) {
 var res = _.find(list, function(val){ return _.isEqual(obj, val)});
 return (_.isObject(res))? true:false;
}

please refer to underscore.js documentation for the underscore functions used in the above example.

note: This is not a pure javascript solution. Shared for educational purposes.

Jinesh
  • 2,507
  • 2
  • 22
  • 23
9

I would use a generic iterator of property/value over the array. No jQuery required.

arr = [{prop1: 'val1', prop2: 'val2'}, {prop1: 'val3', prop2: 'val4'}];

objectPropInArray(arr, 'prop1', 'val3'); // <-- returns true

function objectPropInArray(list, prop, val) {
  if (list.length > 0 ) {
    for (i in list) {
      if (list[i][prop] === val) {
        return true;
      }
    }
  }
  return false;  
}
sampathsris
  • 21,564
  • 12
  • 71
  • 98
Deiu
  • 517
  • 5
  • 4
9

You can just use the equality operator: ==. Objects are checked by reference by default, so you don't even need to use the === operator.

try this, just make sure you're using the correct variable reference in the place of car1:

var i, car, l = cars.length;

for (i = 0; i < l; i++)
{
  if ((car = cars[i]) == car1)
  {
    break;
  }
  else car = null;
}

Edit to add:

An array extension was mentioned, so here's the code for it:

Array.prototype.contains = Array.prototype.contains || function(obj)
{
  var i, l = this.length;
  for (i = 0; i < l; i++)
  {
    if (this[i] == obj) return true;
  }
  return false;
};

Note that I'm caching the length value, as the Array's length property is actually an accessor, which is marginally slower than an internal variable.

FabianCook
  • 20,269
  • 16
  • 67
  • 115
zzzzBov
  • 174,988
  • 54
  • 320
  • 367
  • Since you brought it up. Faster to loop backwards with a while. `var i = this.length; while (i--) { ... };` Since going backwards won't hurt here, may as well. http://ajaxian.com/archives/fast-loops-in-js – Hemlock Jan 03 '11 at 18:40
  • @Hemlock good point, except it'd have to be `this[i-1]` in the loop. – zzzzBov Jan 03 '11 at 18:50
  • Nope, look again. i gets decremented after it gets tested. – Hemlock Jan 03 '11 at 19:13
  • 1
    *"You can just use the equality operator: `==`. Objects are checked by reference by default, so you don't even need to use the `===` operator."* I would advise strongly against using the `==` operator anywhere. It isn't even transitive! – cdhowie Nov 16 '15 at 21:11
5

try this , You can use the JavaScript some() method to find out if a JavaScript array contains an object.

<script>
// An array of objects
var persons = [{name: "Harry"}, {name: "Alice"}, {name: "Peter"}];

// Find if the array contains an object by comparing the property value
if(persons.some(person => person.name === "Peter")){
    alert("Object found inside the array.");
} else{
    alert("Object not found.");
}
</script>
Mohammad Nadr
  • 111
  • 1
  • 4
  • Note that if try to find the object inside an array using the indexOf() method like persons.indexOf({name: "Harry"}) it will not work (always return -1). Because, two distinct objects are not equal even if they look the same – Mohammad Nadr Aug 14 '22 at 12:08
4

You could try sorting the array based on a property, like so:

carBrands = carBrands.sort(function(x,y){
  return (x == y) ? 0 : (x > y) ? 1 : -1;
});

Then you can use an iterative routine to check whether

carBrands[Math.floor(carBrands.length/2)] 
// change carBrands.length to a var that keeps 
// getting divided by 2 until result is the target 
// or no valid target exists

is greater or lesser than the target, and so on, which will let you go through the array quickly to find whether the object exists or not.

Robusto
  • 31,447
  • 8
  • 56
  • 77
3

EDIT 05/18/2022

The most simple way using ES6:

const arrayContainsObject = <T extends Record<string, unknown>>(array: T[], object: T) => {
  return array.some(item => Object.keys(item).every(key => item[key] === object[key]))
}

Use like so:

const arr = [{
  prop1: 'value1',
  prop2: 'value2'
}]
const obj1 = {
  prop1: 'value1',
  prop2: 'value2'
}
const obj2 = {
  prop2: 'value2',
  prop1: 'value1'
}
const obj3 = {
  prop0: 'value0',
  prop1: 'value1'
}
arrayContainsObject(arr, obj1) // true
arrayContainsObject(arr, obj2) // true, even when props are arranged in different order
arrayContainsObject(arr, obj3) // false


Previous answer, don't use (because the order of props in an object needs to be identical)

const arr = [{
  prop: 'value'
}]
const obj = {
  prop: 'value'
}
arr.some((e) => Object.entries(e).toString() === Object.entries(obj).toString()) // true
Leon Vogler
  • 532
  • 4
  • 10
2

You can convert both the JSON objects to string and simply check if the bigger json contains the smaller json.

console.log(JSON.stringify(carBrands).includes(JSON.stringify(car1))); // true

console.log(JSON.stringify(carBrands).includes(JSON.stringify(car5))); // false
Harshita Sethi
  • 2,035
  • 3
  • 24
  • 46
1

i know this is an old post, but i wanted to provide a JQuery plugin version and my code.

// Find the first occurrence of object in list, Similar to $.grep, but stops searching 
function findFirst(a,b){
var i; for (i = 0; i < a.length; ++i) { if (b(a[i], i)) return a[i]; } return undefined;
}

usage:

var product = $.findFirst(arrProducts, function(p) { return p.id == 10 });
Rafael Herscovici
  • 16,558
  • 19
  • 65
  • 93
1

This function is to check for a unique field. Arg 1: the array with selected data Arg 2: key to check Arg 3: value that must be "validated"

function objectUnique( array, field, value )
{
    var unique = true;
    array.forEach(function ( entry )
    {
        if ( entry[field] == value )
        {
            unique = false;
        }
    });

    return unique;
}
Donny van V
  • 921
  • 1
  • 10
  • 22
1

you can use Array.find().

in your case is going to look like this

carBrands.find(function(car){
    let result  = car.name === 'ford'
    if (result == null){
        return false;
    } else {
        return true
    }
});

if car is not null it will return the javaScript Object which contains the string 'ford'

about14sheep
  • 1,813
  • 1
  • 11
  • 18
1

The issue with many of the answers here is that they will NOT find an object in an array that is equal to another object. They will only search for an EXISTING object that has a pointer to it in an array.

Quick fix using lodash to see if ANY equal object is in an array:

import _ from 'lodash';
_.find(carBrands, car1); //returns object if true, undefined if false

Working Plunker using this method: https://plnkr.co/edit/y2YX9o7zkQa2r7lJ

GavinBelson
  • 2,514
  • 25
  • 36
0

if its possible to use es6

carBrands.filter(carBrand => carBrand.name === carX.name).length > 0

if it's true there is a similarity

Amir
  • 41
  • 3
0

You could also a the findIndex

var carBrands = [];

var car1 = {name:'ford'};
var car2 = {name:'lexus'};

carBrands.push(car1);

if (carBrands.findIndex(f => f.name === car1.name) === -1) { 
  console.log('not contain')
} else {
  console.log('contain')
}


if (carBrands.findIndex(f => f.name === car2.name) === -1) { 
  console.log('not contain')
} else {
  console.log('contain')
}