Cover

Need LINQ but Writing JavaScript?

August 11, 2013
No Comments.

One of the tasks that I found cumbersome when writing JavaScript is simple collection manipulation. I have gotten spoiled in C# with LINQ. Sorting, filtering, shaping and more is easy with LINQ but what about in JavaScript? Underscore.js to the rescue.

Underscore.js is a small utility library that can help in collection manipulation (as well as other great features). I first started using Underscore.js to replace jQuery’s (and AngularJS’s) for-each implementations. I find underscore’s simple and quick. Like much of JavaScript, the magic is happening in a callback function (think Lambda):

var a = [1, 2, 3, 4, 5];

_.each(a, function (i) {
    console.log("each: " + i);
    // Break out of loop by returning false
    if (i > 3) return false; // doesn't work 
});

Note that the “_” is an aliased object that exposes most of the Underscore.js behavor (e.g. functions). So _.each is a function on the underscore object (e.g. “_”).

That works great, but I can’t break out of it like I can in jQuery…so Underscore.js’ _.every function to the rescue:

var a = [1, 2, 3, 4, 5];

// Faking out the behavior
_.every(a, function (i) {
    // Break out of loop by returning false
    if (i > 3) return false; // works 
    console.log("every: " + i);
    return true; // Continues the every
});

But that’s just the tip of the iceberg of goodness. When you’re dealing with a more nuanced collection (e.g. like one from an API call, you may want to manipulate it in memory. Here’s the data we’re starting from:

var data = [{
    name: "Freddy Freeman",
    position: "1B",
    team: "ATL",
    stats: {
        avg: .310,
        hr: 13,
        r: 63,
        rbi: 76
    }
}, {
    name: "Chris Johnson",
    position: "3B",
    team: "ATL",
    stats: {
        avg: .337,
        hr: 8,
        r: 43,
        rbi: 45
    }
}, {
    name: "Brian McCann",
    position: "C",
    team: "ATL",
    stats: {
        avg: .277,
        hr: 17,
        r: 31,
        rbi: 45
    }
}, {
    name: "Andrelton Simmons",
    position: "SS",
    team: "ATL",
    stats: {
        avg: .245,
        hr: 11,
        r: 60,
        rbi: 40
    }
}, {
    name: "Jason Heyward",
    position: "RF",
    team: "ATL",
    stats: {
        avg: .238,
        hr: 10,
        r: 52,
        rbi: 32
    }
}, ];

This is simple data but we’d like to be able to perform some set operations like sorting, filters and others. Let’s start with sorting. To sort, we simply call _.sortBy which takes a collection (anything iterable) and a callback that accepts each item in the collection like so:

var sorted = _.sortBy(data, function (i) { return i.name; });

In this example our collection (the data object) is passed in as the first parameter and the callback function is the second parameter. We’re returning the name property because that’s what we want to sort by.  Look familiar? It should.

How about filtering?

var filtered = _.filter(data, function (i) { return i.stats.avg > .300; });

In this example, we’re filtering by returning a Boolean value on whether to include the item in the filtered results.

Underscore.js includes other really useful items like map, reduce, find, contains, min, max and others. It really enables many of the scenarios that I’d use LINQ in C# (or VB.NET).  But these examples so far show only a single operation. What about when you want to perform a series of operations (which is often the norm)?  _.chain to the rescue:

var chained = _.chain(data)
    .filter(function (i) { return i.stats.avg < .300; })
    .sortBy(function (i) { return i.name; })
    .value();

```csharp



**\_.chain **allows you to specify a collection (e.g. data) and then call multiple operations on that collection. You must end the set of operations to a call to** .value** to complete the chain of operations. By using chain, you can perform a series of operations and easily do LINQ-like functionality. You can get Underscore.js here (and the docs including a great annotated source):


> [http://underscorejs.org](http://underscorejs.org)


If you want to play with it, I have a JSFiddle here with the code I've been discussing:

<iframe height="300" src="http://jsfiddle.net/shawnwildermuth/v9Urs/3/embedded/" frameborder="0" width="100%" allowfullscreen="allowfullscreen"></iframe>



What do you think?