Examples of the _.find collection method in lodash

So there is the old do I use objects or arrays problem that I run into when working on a project. Of course arrays are objects, but I gather that you may know what I mean if you are like me, and have been coding with javaScript for a few years. I try not to get caught up on these things, it does not matter a whole lot, plus there are ways of always dealing with whatever it may be anyway. As such methods like _.find in lodash come in handy for this kind of thing.

_.find vs Array.find

So yes there is of course Array.find, and Array.find works just fine with Arrays:

1
2
3
4
5
6
7
8
9
var arr = ['a',1,'b','c'];
var n = arr.find(function(el){
return typeof el === 'number';
});
console.log(n); // 1

It also works well with array like objects when used with call.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var obj = {
0 : 'bar',
1: 42,
length: 2
};
var n = [].find.call(obj, function(el){
return typeof el === 'number';
});
console.log(n); // 42

However _.find is a collection method, not an Array method. So in addition to working just fine with Arrays _.find works with plan old objects as well, even if they are not array like.

1
2
3
4
5
6
7
8
9
10
11
12
var n = _.find({
foo: 'bar',
n: 42
},function(el){
return typeof el === 'number';
});
console.log(n); // 42

Also there is the built in iteration methods that can come in handy. The potential for better backward compatibility with old versions of IE if for some reason that is a concern. Also this is a lodash post, so…

What a collection is, and basic example

The lodash _.find method works not just with Arrays but also any object, so _.find is considered one of the many collection methods in lodash. So find can help solve that problem when it comes to choosing between using Arrays and plain old Objects, as in any case I can use _.find to get at what I want in an Object of any kind, not just an Array.

So the first argument that is given to _.find is a collection, which can be an Array, an Array like object, just a plain old Object, and even Strings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// The is an Object that is an Array that
// is a kind of collection
var anArray = ['i', 'am', 'an', 'Array'];
console.log(anArray.constructor.name); // Array
// This is an Object that is an Object
// but it is an collection that is 'Array like'
var notAnArray = {
0: 'i',
1: 'am',
2: 'not',
3: 'an',
4: 'Array'
};
console.log(notAnArray.constructor.name); // Object
// This is an Object that is not at all like an Array
// It is a collection of key value pairs though
var soNotAnArray = {
foo: 'totally',
bar: 'not',
man: 'an',
chew: 'Array'
};
console.log(soNotAnArray.constructor.name); // Object
// this is a method that I can pass to _.find
// along with a collection that will give me the first
// element that has a length greater than 3
var method = function (el) {
return el.length >= 3;
};
console.log( _.find(anArray, method) ); // Array
console.log( _.find(notAnArray, method) ); // not
console.log( _.find(soNotAnArray, method) ); // totally

The iteration method

The second argument that is given to _.find is an iteration method, or some kind of short hand for such a method. This method can have three arguments, the first of which is the current element in the collection that is being looked at. In addition the second argument is the current index, and the last argument is a reference to the collection that was given.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var result = _.find(['a', 'b', 'c'], function (el, i, col) {
// first argument is the current collection element 'a' - 'c'
console.log(el);
// second argument is the current index 0 - 2
console.log(i);
// third argument is the actual collection ['a','b','c']
console.log(col);
// if true is returned, then that is what
// will be returned by _.find, else it will keep looking
return el === 'b'
});
console.log(result); // b

In the body of the iteration method, if what is returned by the method evaluates to true then, then that will count as the element being found.

Custom iteration methods and lodash method shorthands

As shown above I can make my own methods that are used to define the terms of whether or not an element in a collection is what it is that I am looking for. I can of course make a method that returns a iteration method that _.find can use. However I might not even have to do that if such a method is in lodash to begin with, and there are even some shorthands that can be used in _.find that allow for me to not even have to call the lodash method directly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// say I have an array with some data like this
var data = ['talk', 'run', {action: 'walk'}, {action: 'sing'}, {action: 'dance'}],
// sure I can make my own methods that
// make use of closure...
findProperty = function (propName) {
// ...that when called pass a function that
// _.find can use
return function (el, i, col) {
if (typeof el === 'object') {
return propName in el;
}
};
};
// and find will use it.
console.log( _.find(data, findProperty('action')) ); // {action:'walk'}
// but there is a lodash method for that to begin with
// called _.property
console.log( _.find(data, _.property('action') ) ); // {action:'walk'}
// and why even bother with that when there is
// a short hand for it.
console.log( _.find(data, 'action') ); // {action:'walk'}

In addition to shorthands for _.property there are also shorthands for _.matches _.matchesProperty.

1
2
3
4
5
// _.matchesProperty
console.log( _.find(data, ['action','sing']) ); // {action:'sing'}
// _.matches
console.log( _.find(data, {action:'dance'}) ); // {action:'dance'}

FromIndex example

This lodash method can accept a third argument that is the index where to start looking in the collection.

1
2
3
4
5
6
7
8
9
10
11
12
13
var collection = [1,2,3,4,5,'a','b','c'],
method = function(el,i){
if(typeof el === 'string'){
return true;
}
};
console.log( _.find(collection, method) ); // 'a'
console.log( _.find(collection, method , 6) ); // 'b'

Finding an Object in an Array, a basic usage example of _.find

So _.find will help with returning an element in an array, rather than it’s index. So if you have an array of objects and you want to find a single object in the array by a certain key value pare _.find is the right tools for the job.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var db_array = [
{
name : 'Dave',
sex : 'male',
age : 34
},
{
name: 'Jake',
sex : 'male',
age : 22
},
{
name :'Jane',
sex : 'female',
age : 27
}
],
// find dave
q = _.find(db_array, {name:'Dave'});
console.log(q); // {name:'Dave',sex:male,age:34}

You do not have to give an object, you can also use a function like this.

1
2
3
q = _.find(db_array, function (obj) {
return obj.name === 'Dave';
});

Using _.find to find the index of an element in an Array, or the key of a property in an Object.

In lodash there is the _.findIndex method, that works just fine with Arrays, as it is an Array method. However it will not work with Objects in general, as it is not a collection method. It is possible to use _.find to get the index of an element in an Array, or the key of a property in any Object. As you might have read earlier in this post the second argument that is given in the iteration method is the index, or key value if it is a plain Object.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
var arr = ['foo', 'man', 'chew'],
index = -1;
// using _.find to find an index, or key value
var findIndex = function (col, what) {
var index = -1;
// _.find will return the value
// but the index or key is one of the values
// in the iteration method
_.find(col, function (el, iKey) {
index = iKey;
return el === what;
});
// return the result
return index;
};
// this will return the index, or key
console.log(findIndex(arr, 'man')); // 1
console.log(findIndex({
what: 'foo',
how: 'bar'
}, 'bar')); // 'how'
// there is also the _.findIndex method
var findIndex = function (col, what) {
// _.findIndex will return an index, rather than a value
return _.findIndex(col, function (el, i) {
console.log('i=' + i);
return el === what;
});
};
// _.findIndex works fine with arrays
console.log(findIndex(arr, 'man')); // 1
// but it is an array method, so it will only work with arrays
console.log(findIndex({what: 'foo',how: 'bar'}, 'bar')); // -1

Using _.find on an array of primitives, and a single primitive.

Find is fairly robust, of course it can be used with an array of primitives.

1
2
3
4
5
6
7
8
9
10
11
12
13
var words = ['foo**', '*foo*', '**foo'];
var result = _.find(words, function (str, i) {
if (str.match(/\*\*foo/)){
return true;
}
});
console.log(result); // '**foo'

However _.find can be used on a single stand alone String as well

1
2
3
4
5
6
7
var str = 'This is a single string! Yes it can be used with find.';
console.log( _.find(str,function(el,i,col){
return el === '!';
}) ); // !

This is because strings are also another example of something in javaScript that is kindof Array like, even though it is not an array. Sure it’s constructor is String, and not Array as such it does not have array methods in it’s prototype. However it can still be thought of as an array of characters.

Conclusion

Many of the methods in lodash provide functionality that is very similar to certain native methods, but often they do bring a little something more to the table.

I have updated this post a few times now, and I will likely update this post again in the future once again at some point. If you are in the mood check out my other posts on lodash.