Press "Enter" to skip to content

Comparing underscore.js with Linq

vpandzic 0

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: https://github.com/kutyel/linq.ts. 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?

 

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.

FirstOrDefault()/Find

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:

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.

Using ES6 this would be ever shorter:

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

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/ _.map

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

So example from above example could look likes this:

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

In underscore.js _.map 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:

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

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.

Idea is to now use _.flatten to flatten list of users and get list of 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.

To sort users by Name in descending order:

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]

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.

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.

Max Min/ _.max _.min

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

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.

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.

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:

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

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.

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

Aggregate/ _.reduce

_.reduce is similar to _.map 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.

 

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 *