Lodash _.find collection method examples with vanilla js alternatives.

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.

1 - lodash find method and alternatives

So the lodash _.find method is a nice little method that works in a very similar fashion to the Array.find method in core javaScript. However the Array.find method is an array protoype method and not a collection with like with _.find in lodash. So there is more that the _.find brings to the table compared to the native array method alternative, and in this post I will be pointing out what these features are that set ot array from Array.find.

Still it is not to hard to just find something in an array with just plain old javaScript by itself, in many cases the native Array.find method will work just fine, and in some cases it is possible to get it working with array like objects as well. So in this post I will also be writing about some plain old vanilla js ways of finding an object or something to that effect with plain javaScript as well.

2 - _.find vs Array.find

So there seems to be a lot of debate these days where it comes to lodash even being relevant or necessary when it comes to writing modern javaScript. It is true that a lot of the functionality in lodash is now baked into core javaScript itself. So there are many methods in lodash that are not really needed any more, if a developer is only concerned about supporting modern evergreen browsers as least.

However there are some methods that are not a part of core javaScript at all, and there are many methods where there is a native counterpart, but it works just a little differently, brings some more features, is a little more robust and so forth. That being said the lodash _.find method is one of those methods and in this section I will be pointing out some of the deferences between _.find and the native Array.find method.

2.1 - Native Array.find overview

So yes there is of course Array.find, and Array.find works just fine with arrays. Just call the find prototype method off of an instance of any plain old javaScript array as with any Array prototype method, and pass a function that will be used to find what it is that needs to be found in the Array.

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

In this example I just have a simple array of primitives. I which to just find the first element in the array that is a number. I just need to use the typeof operator when making an expression that will return true when an element is found that is a number. In more complex situations involving arrays of objects for example the function that I pass might be a bot more complex, but you get the basic idea.

2.2 - Array.find with Array like objects

It also works well with array like objects when used with call. If you are not aware of what array like objects are they are it is a trem that if often used to describe an object that is formated very much like an Array in that all of the object keys are numbers, and it has a length property. However the so called array like object is not an instance of the Array constructor so it does not have Array prototype methods associated with it.

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

2.3 - Lodash _.find will work with Arrays, Array like Objects and plain old objects in general as well.

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…

3 - 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

4 - 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.

5 - 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'}

6 - 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'

7 - 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';
});

8 - 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

9 - 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. However it can also be used with a single string primitive as well.

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. The reason why is that a although a string is a primitive it can be treaded as a collection of characters.

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.

10 - Vanilla javaScript and finding things in an array

Depending on what needs to happen sometimes finding something in an array is really not all that hard. With simple hobby projects and so forth often just a loop and a conditional will get the job done. In some cases I might want to write my my own custom find method when making some kind of module or something to that effect as well. In a previous section I covered the native Array.find method well but in this section I will cover some more ways of finding things with just plain old javaScript by itself.

10.1 - Using a for in loop

So it is not to hard to make a find method that works in a similar way to that of the lodash find method. The for in loop is of course one way to go about looping over the public key value pairs of any object in javaScript. So the for in loop can be used as a way to make a collection method that will work okay for any kind of object, not just Arrays. There are performance concerns with for in, but for many projects it will work okay when performance is not of grave concern.

Making a basic find method with for in might look something like this:

1
2
3
4
5
6
7
8
9
10
// crude yet effective find method
let find = function (col, forEach) {
let prop;
for (prop in col) {
if (forEach(col[prop], prop)) {
return col[prop];
}
}
return false;
};

The find method can then be used on an array of objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// array of objects
let people = [{
name: 'John',
age: 32,
sex: 'M'
}, {
name: 'Mike',
age: 24,
sex: 'M'
}, {
name: 'Jen',
age: 42,
sex: 'F'
}
];
// works with array of objects
var mike = find(people, function (val, key) {
if (val.age === 24) {
return true;
}
return false;
});
console.log(mike.age); // 24

Or just a plain old object by itself than can be thought of as a kind of associative array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Just an object
let obj = {
foo: 'bar',
salty: true,
n: 42
};
var aNumber = find(obj, function (val, key) {
if (typeof val === 'number') {
return true;
}
});
console.log(aNumber); // 42

10.2 - Using Object.keys

Another approach to making a find method might be to use an Object static method like Object.keys which can be used to get an array of key names of any object. The key names will be any public key of the object that is passed to it. This array can then be looped over, and a condition can be used to find out if this is an example of something that is to be found.

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
var find = function (col, forEach) {
var keys = Object.keys(col),
i = keys.length,
results = [];
while (i--) {
if (forEach(col[keys[i]], keys[i])) {
results.push(col[keys[i]]);
}
}
return results;
};
var nums = [7, 8, 13, -5, 32, 2.5];
var pow2 = find(nums, function (val, key) {
var p = Math.log(val) / Math.log(2);
return p > 0 && String(p).indexOf('.') === -1;
});
console.log(pow2); // [32,8]
var obj = {
foo: 'bar',
n: 42,
mess: 'hello world',
bar: true,
baz: null
};
var strings = find(obj, function (val) {
return typeof val === 'string';
});
console.log(strings); // ['hello world', 'bar']

11 - 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.