Comparing underscore.js with Linq

If you are .NET developer you are probably spoiled by how it is easy to manipulate collections using LINQ. However, if you are full stack developer and write a lot of Javascript you know that is not elegant to manipulate collections in JavaScript. It is possible to use TypeScriptand use something like: However, topic of this post is not about TypeScript and linq.ts library. It is another library often used by Javascript developer and it is called underscore.js.

Looking familiar?

import { List } from 'linqts';

let arr = new List<number>([1, 2, 3, 4, 5])
    .Where(x => x > 3)
    .Select(y => y * 2)
    .ToArray(); // > [8, 10]

let query = people.Join(pets,
    person => person,
    pet => pet.Owner,
    (person, pet) =>
        ({ OwnerName: person.Name, Pet: pet.Name }));


Underscore.js has over 100 helper function that will help you in your Javascript development.

Lets see some of those functions and also try to compare it with it’s .NET version.


var user = users.Where(x=>x.Name="John").FirstOrDefault();
var user=_.find(users,function(user){return user.Name=="John"});

FirstOrDefault() returns null if there is no match otherwise returns first user that match criteria. Similary, _.find will work the same way returning undefined if there is no match.

There are different styles of writing this code, using LINQ and undercore.js.

It was possible to write LINQ version like this:

var user = users.FirstOrDefault(x=>x.Name="John");

 It as mather of personal preference but I find that first one reads more naturally.

Underscore offers two different syntax styles, a functional syntax and an object-oriented syntax. Again, it is mather of personal preference. Example from above would look like this if is was written using object-oriented syntax.

var user=_(users).find(function(user){return user.Name=="John"});

Using ES6 this would be ever shorter:

var user=_(users).find(x=>x.Name=="John"});

Notice, how by combining of using object-oriented undercore.js syntax together with ES6 code resambles C# code and LINQ but in this articles we will stick to ES5 as ES6 is supported by new browsers only.

Where()/ _.filter

var user=users.Where(x=>x.Name=="John").ToList();
var user=_.filter(users,function(user){return user.Name=="John"});

Where and ._filter return all users that match criteria. If any user match criteria empty list will be returned in both LINQ and underscore.js.

ToList() is not just about converting collection to List. It forces immediate query execution, so if for example users are fetched from the database ToList() will actually send query to database and convert result to List.


Select in LINQ and in undrescore are completely different. While Select in LINQ is used for projections in underscore.js is used for filtering. In fact is just alias for _.filter.

So example from above example could look likes this:

var user=_.filter(users,function(user){return user.Name=="John"});
var,function(user){return user.Name=="John"});

Lets imagine each user has Id,Name,SurName properties and we want to make list of all ids (project the list to the new one that contains only Id property. We would use Select in .NET

var ids=users.Select(x=>new {x.Id}).ToList();
var,function(user){return user.Id});

In underscore.js alias _.collect is used.

SelectMany()/_.flatten and _.pluck

Let’s imagine each user from examples above has Products property(of type List in C# and Array in JavaScript). To get list of all products of all users you can flatten list of users like this:

var allProducts=users.SelectMany(x=>x.Products).ToList();
var allProducts=_.flatten(_.pluck(users,'Products'));

To achieve some functionality that SelectMany has first idea was to use just _.flatten like so:

var notworking=_.flatten(users,'Products')); //NOT POSSIBLE

This is not possible because you can’t tell _.flatten on which property to flatten on but there is one function that does exactly that – it’s called _.pluck. “Problem” with _.pluck in this case is that does not change original structure when we pluck users. We are still getting list of users but we “removed” all other properties.

var usersWithJustProductsProperty=_.pluck(users,'Products')); //LIST OF //USERS WITH JUST PRODUCTS PROPERTY

Idea is to now use _.flatten to flatten list of users and get list of products:

var allProducts=_.flatten(_.pluck(users,'Products'));

OrderBy/ _.sort

OrderBy in LINQ and _.sort in underscore.js work similar to each other. Both will return a copy of list sorted in ascending order. However, there is no underscore.js alternative to OrderByDescending but javascript’s reverse() method can be used to achieve similar result.

var sortedUsers=users.OrderBy(x=>x.Name);
var sortedUsers=_.sortBy(users,'Name');

To sort users by Name in descending order:

var sortedUsers=users.OrderByDescending(x=>x.Name);
var sortedUsers=_.sortBy(users,'Name').reverse();

ForEach/ _.each

ForEach and _.each are very similar. Both can perform an operation on each item in te list. They don’t returning anything.


Intersect/ _.intersection

Both methods return new list that contains all elements that exist in each individual list.
For example:

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]

var sharedUsers= users.Intersect(users2List);
var sharedUsers= _.intersection(users,users2List);

If we want to make intersection between multiple list syntax is then little bit different. Underscore.js accepts the list of lists while in LINQ we have to chain Intersect calls.

var sharedUsers= users.Intersect(users2List).Intersect(users3List);
var sharedUsers= _.intersection(users,users2List,users3List);

Except/ _.difference

Except and _.difference are opposite of Intesect and _.intersection. They return the values from array that are not present in the other arrays.

var differentUsers= users.Except(users2List);
var differentUsers= _.difference(users,users2List);

Max Min/ _.max _.min

Max returns maximum element in list, minimul returns minimum element in list, as simple as that.

var minId= users.Min(x=>x.Id);
var maxId= users.Max(x=>x.Id);
var minId= _.min(users,function(user){return user.Id});
var maxId= _.max(users,function(user){return user.Id});

Any / _.any (_.some)

Any returns true if at least one element in list satisfy condition specifed by the iterator of the function. _.any has alias _.some in underscore.js. Enumeration will stop if test evaluates to true.

var existsAtLeastOneDeletedUser= users.Any(x=>x.Deleted==true);

var existsAtLeastOneDeletedUser= _.any(users,function(user){return user.Deleted==true});

All/ _.all

All returns true if all elements in list satisfy condition specified by the iterator of the function. _.all has alias _.every in underscore.js.

var areAllUsersDeleted= users.All(x=>x.Deleted==true);

var areAllUsersDeleted= _.all(users,function(user){return user.Deleted==true});

DistinctBy (not exist, but…)/ _.uniq

DistinctBy and _.uniq remove duplicates from the list.
Unfortunatelly DistincyBy does not exist in LINQ although it is easy to write own extension method on List. Other solution would be to use more linq which has that method or combine other LINQ functions together:

List<User> distinctPeople = users
.GroupBy(p => p.Id)
.Select(g => g.First())

_.uniq works this way:

Produces a duplicate-free version of the array, using === to test object equality. In particular only the first occurence of each value is kept. If you know in advance that the array is sorted, passing true for isSorted will run a much faster algorithm. If you want to compute unique items based on a transformation, pass an iteratee function.

List<User> distinctPeople = users
.GroupBy(p => p.Id)
.Select(g => g.First())

var distinctPeople = _.uniq(users, function(user, key, a) {
return user.Id;

FindIndex/ _.indexOf

FindIndex searches for an element that matches the conditions defined by a specified predicate, and returns the zero-based index of the first occurrence within the List or a portion of it. This method returns -1 if an item that matches the conditions is not found. This method performs a linear search; therefore, this method is an O(n) operation, where n is Count. _.indexOf works similary and can also accept third argument of value true if we know in advance that list is sorted to use faster binary search. Similar to _.indexOf,_.findIndex returns the first index where the predicate truth test passes; otherwise returns -1.

var index=users.FindIndex(x=>x.Name=="John");

var index= _.findIndex(users, function(user) {
return user.Name=="John";

Now when we know how _.pluck and ._indexOf work this can be achieved also by combining those two functions:

var index= _.indexOf(_.pluck(users,'Name'),"John");

Aggregate/ _.reduce

_.reduce is similar to except that instead of producing another functor _.reduce produces a single result that may be of any type.
Let’s is it’s definition from undercore.js documentation:

reduce_.reduce(list, iteratee, [memo], [context]) Aliases: inject, foldl

Also known as inject and foldl, reduce boils down a list of values into a single value. Memo is the initial state of the reduction, and each successive step of it should be returned by iteratee. The iteratee is passed four arguments: the memo, then the value and index (or key) of the iteration, and finally a reference to the entire list.

var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
=> 6

C# version of _.reduce is Aggregate function. It is very similar to _.reduce in a way that first parametar of iterator function is memo and second is current item of the list.

var totalPoints=users.Aggregate((memo,user)=>memo+user.Points);

var totalPoints= _.reduce(users, function(memo,user) {
return memo+user.Name;


There are more of LINQ and underscore.js operators and similarities between them but I think I covered methods that are most often used. As you can see there are lot of similarities between them and knowing LINQ will help you learn underscore.js faster.

Leave a Reply

Your email address will not be published. Required fields are marked *.

You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>