187

lodash lets me check for membership of basic data types with includes:

_.includes([1, 2, 3], 2)
> true

But the following doesn't work:

_.includes([{"a": 1}, {"b": 2}], {"b": 2})
> false

This confuses me because the following methods that search through a collection seem to do just fine:

_.where([{"a": 1}, {"b": 2}], {"b": 2})
> {"b": 2}
_.find([{"a": 1}, {"b": 2}], {"b": 2})
> {"b": 2}

What am I doing wrong? How do I check for the membership of an object in a collection with includes ?

edit: question was originally for for lodash version 2.4.1, updated for lodash 4.0.0

Conrad.Dean
  • 4,341
  • 3
  • 32
  • 41
  • 8
    `_.contains` has been removed in lodash v4 - use [`_.includes`](https://lodash.com/docs#includes) instead – Billy Moon Feb 11 '16 at 09:14
  • @BillyMoon woops! yeah you're right, lodash v4.0.0 (released 2016-01-12) removes the `contains` alias. I'll update this – Conrad.Dean Feb 11 '16 at 17:00

3 Answers3

284

The includes (formerly called contains and include) method compares objects by reference (or more precisely, with ===). Because the two object literals of {"b": 2} in your example represent different instances, they are not equal. Notice:

({"b": 2} === {"b": 2})
> false

However, this will work because there is only one instance of {"b": 2}:

var a = {"a": 1}, b = {"b": 2};
_.includes([a, b], b);
> true

On the other hand, the where(deprecated in v4) and find methods compare objects by their properties, so they don't require reference equality. As an alternative to includes, you might want to try some (also aliased as any):

_.some([{"a": 1}, {"b": 2}], {"b": 2})
> true
fodma1
  • 3,485
  • 1
  • 29
  • 49
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
17

Supplementing the answer by p.s.w.g, here are three other ways for achieving this using lodash 4.17.5, without using _.includes():

Say you want to add an object entry to an array of objects numbers, only if entry does not exist already.

let numbers = [
    { to: 1, from: 2 },
    { to: 3, from: 4 },
    { to: 5, from: 6 },
    { to: 7, from: 8 },
    { to: 1, from: 2 } // intentionally added duplicate
];

let entry = { to: 1, from: 2 };

/* 
 * 1. This will return the *index of the first* element that matches:
 */
_.findIndex(numbers, (o) => { return _.isMatch(o, entry) });
// output: 0


/* 
 * 2. This will return the entry that matches. Even if the entry exists
 *    multiple time, it is only returned once.
 */
_.find(numbers, (o) => { return _.isMatch(o, entry) });
// output: {to: 1, from: 2}


/* 
 * 3. This will return an array of objects containing all the matches.
 *    If an entry exists multiple times, if is returned multiple times.
 */
_.filter(numbers, _.matches(entry));
// output: [{to: 1, from: 2}, {to: 1, from: 2}]

If you want to return a Boolean, in the first case, you can check the index that is being returned:

_.findIndex(numbers, (o) => { return _.isMatch(o, entry) }) > -1;
// output: true
Mihai
  • 2,807
  • 4
  • 28
  • 53
4

You could use find to solve your problem

https://lodash.com/docs/#find

const data = [{"a": 1}, {"b": 2}]
const item = {"b": 2}


find(data, item)
// (*): Returns the matched element, else undefined.

nassim miled
  • 581
  • 1
  • 6
  • 18