← Go Back

How to Implement LINQ methods in JavaScript - Part 1

Broken Post?Let me know

Photo by Simon Migaj on Unsplash LINQ has been around since 2007. It made the code more readable as you specify what you do with a collection not how to process it.JavaScript is the de facto standard so you should be working with it often if you are doing web development.

I will share some "approximate" JavaScript equivalents below for those working primarily with .NET but want to use the existing skill in JavaScript.

Since each method do not match exactly one to one functionality wise, I will drop "approximate" hereafter.

Here are the methods covered so far.

  1. Part 1 〰️ Select, Aggregate, Where, OrderBy (Ascending, Descending)
  2. Part 2 〰️ Any, Distinct, Concat, SelectMany
  3. Part 3 〰️ Reverse, Zip, Min/Max
  4. Part 4 〰️ Union, Intersect, Except
  5. Part 5 〰️ Sum, Average, Count
  6. Part 6 〰️ First, Last, DefaultIfEmpty, Skip, Take
  7. Part 7 〰️ Empty, Repeat, Range
  8. Part 8 〰️ All, Contains, SequenceEqual

🔴 Overview

Here are the examples I will show you in this article. [table id=1]

I tried to match the code look similar to each other (as you can see the full source codes in LINQ & JavaScript on GitHub).

Here are the sample collections I will use to demo each method.

CSharp

private static List<Order> Orders = new List<Order>{
new Order(id: 1, quantity: 40, orderDate: new DateTime(2018, 1,1,1,1,1,1)),
new Order(id: 2, quantity: 20, orderDate: new DateTime(2018, 2,2,2,2,2,2)),
new Order(id: 3, quantity: 30, orderDate: new DateTime(2018, 3,3,3,3,3,3)),
new Order(id: 4, quantity: 10, orderDate: new DateTime(2018, 4,4,4,4,4,4)),
new Order(id: 5, quantity: 20, orderDate: new DateTime(2018, 5,5,5,5,5,5)),
};
view raw Orders.cs hosted with ❤ by GitHub

JavaScript

const orders = [
{ id: 1, quantity: 40, orderDate: new Date(2018, 1, 1, 1, 1, 1) },
{ id: 2, quantity: 20, orderDate: new Date(2018, 2, 2, 2, 2, 2) },
{ id: 3, quantity: 30, orderDate: new Date(2018, 3, 3, 3, 3, 3) },
{ id: 4, quantity: 10, orderDate: new Date(2018, 4, 4, 4, 4, 4) },
{ id: 5, quantity: 20, orderDate: new Date(2018, 5, 5, 5, 5, 5) }
];
view raw orders.js hosted with ❤ by GitHub

🔴 Examples

🔸 Select

map is the equivalent of Select.

private static void SelectDemo(List<Order> orders)
{
var quantities = orders.Select(order => order.Quantity);
quantities.ToList().ForEach(quantity => System.Console.WriteLine($"Quantity: {quantity}"));
}
view raw SelectDemo.cs hosted with ❤ by GitHub

function mapDemo(orders) {
const quantities = orders.map(order => order.quantity);
quantities.forEach(quantity => console.log(`Quantity: ${quantity}`));
}
view raw mapDemo.js hosted with ❤ by GitHub

Syntax-wise, it's basically one-to-one replacement from Select to map. I said "equivalent" but I lied. While map returns a new array, Select has a side effect (it can update the iterating collection). Just remember this difference for the rest of JavaScript methods.

Results of calling SelectDemo and mapDemo.

Quantity: 40
Quantity: 20
Quantity: 30
Quantity: 10
Quantity: 20

🔸 Aggregate

reduce works the same way Aggregate does.

private static void AggregateDemo(List<Order> orders)
{
const int initialQuantity = 0;
var totalQuantities = orders.Aggregate(initialQuantity, (sum, order) => sum + order.Quantity);
// Same as Order simply use a convinient `Sum()` method.
// var totalQuantities = orders.Sum(order => order.Quantity);
System.Console.WriteLine($"Total Quantities: {totalQuantities}");
}
view raw AggregateDemo.cs hosted with ❤ by GitHub

function reduceDemo(orders) {
const initialQuantity = 0;
const totalQuantities = orders.reduce((sum, order) => sum + order.quantity, initialQuantity);
console.log(`Total Quantities: ${totalQuantities}`);
}
view raw reduceDemo.js hosted with ❤ by GitHub

⚡ NOTE ⚡: While the initial value for the accumulator is passed as a first argument in Aggregate, it's passed as the last one in reduce.

Results of calling AggregateDemo and reduceDemo.

Total Quantities: 120

🔸  Where

As you might have guessed it 😉, Where is for filtering records in a collection.  So the equivalent is..., 🎉 filter.

private static void WhereDemo(List<Order> orders)
{
var ordersWithQuantityOver30 = orders.Where(order => order.Quantity > 30);
PrintOrders(ordersWithQuantityOver30);
}
view raw WhereDemo.cs hosted with ❤ by GitHub

function filterDemo(orders) {
const ordersWithQuantityOver30 = orders.filter(order => order.quantity > 30);
printOrders(ordersWithQuantityOver30);
}
view raw filterDemo.js hosted with ❤ by GitHub

Another drop-in replacement of filter for Where. The code so far looked the same thanks to the Lamda expression syntax in both C# & JavaScript (ES6).

Results of calling WhereDemo and filterDemo.

WhereDemo(Orders);
// returns
// Order ID: 1, Quantity: 40, Order Date: 01 Jan 2018 01:01 AM pst
filterDemo(orders);
// returns
// Order ID: 1, Quantity: 40, Order Date: Thu Feb 01 2018 01:01:01 GMT-0500 (Eastern Standard Time)

🔸 OrderBy

Now here is where it gets tricky.

While there are two methods for ordering (ascending/descending) in LINQ, there is only one method in Javascript, sort, which can handle both scenarios.

sort is more roughly equivalent to .NET's Array.Sort method which accepts an object instance of type IComparer<T>, which works the same as a callback in sort.

In the examples below, if the callback, which requires two arguments, returns a value less than 0, then the left value comes before right value, and vice versa. For 0, the order is not changed.

That's why you can emulate OrderBy and OrderByDescending with only sort.

1. Ascending Order

private static void OrderByDemo(List<Order> orders)
{
var orderedOrders = orders.OrderBy(order => order.Quantity);
PrintOrders(orderedOrders);
}
view raw OrderByDemo.cs hosted with ❤ by GitHub

function sortByAscendingDemo(orders) {
// Sorting works by comparing two values in a callback.
// When o1.quantity < 0, then o1 comes before o2.
// When o2.quantity < 0, then o2 comes before o1.
// When o1.quantity === o2.quantity then no change is needed
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
var oderedOrders = orders.sort((o1, o2) => o1.quantity - o2.quantity);
printOrders(oderedOrders);
}

In sortByAscendingDemo, if o1.quantity - o2.quantity returns a negative value, then o1 comes before o2 and vice versa. If quantity in both objects are equal (the difference is 0) then the order is not changed.

Results of calling OrderByDemo and sortByAscendingDemo.

OrderByDemo(Orders);
/* Returns
Order ID: 4, Quantity: 10, Order Date: 04 Apr 2018 04:04 AM pst
Order ID: 2, Quantity: 20, Order Date: 02 Feb 2018 02:02 AM pst
Order ID: 5, Quantity: 20, Order Date: 05 May 2018 05:05 AM pst
Order ID: 3, Quantity: 30, Order Date: 03 Mar 2018 03:03 AM pst
Order ID: 1, Quantity: 40, Order Date: 01 Jan 2018 01:01 AM pst
*/
sortByAscending(orders);
/* Returns
Order ID: 4, Quantity: 10, Order Date: Fri May 04 2018 04:04:04 GMT-0400 (Eastern Daylight Time)
Order ID: 2, Quantity: 20, Order Date: Fri Mar 02 2018 02:02:02 GMT-0500 (Eastern Standard Time)
Order ID: 5, Quantity: 20, Order Date: Tue Jun 05 2018 05:05:05 GMT-0400 (Eastern Daylight Time)
Order ID: 3, Quantity: 30, Order Date: Tue Apr 03 2018 03:03:03 GMT-0400 (Eastern Daylight Time)
Order ID: 1, Quantity: 40, Order Date: Thu Feb 01 2018 01:01:01 GMT-0500 (Eastern Standard Time)
*/

2. Descending Order

private static void OrderByDescendingDemo(List<Order> orders)
{
var orderedOrders = orders.OrderByDescending(order => order.Quantity);
PrintOrders(orderedOrders);
}

function sortByDescendingDemo(orders) {
// Switching o1 & o2 around has the same effect as sorting in descending order
var oderedOrders = orders.sort((o1, o2) => o2.quantity - o1.quantity);
printOrders(oderedOrders);
}

In this JavaScript function, sortByDescendingDemo, two objects are switched from sortByAscendingDemo. To emulate the descending order, we simply switch o1 and o2, which will negate the return values from the callback.

Result of OrderByDescendingDemo and sortByDescendingDemo.

OrderByDescendingDemo(Orders);
/* Returns
Order ID: 1, Quantity: 41, Order Date: 01 Jan 2018 01:01 AM pst
Order ID: 3, Quantity: 31, Order Date: 03 Mar 2018 03:03 AM pst
Order ID: 2, Quantity: 21, Order Date: 02 Feb 2018 02:02 AM pst
Order ID: 5, Quantity: 21, Order Date: 05 May 2018 05:05 AM pst
Order ID: 4, Quantity: 11, Order Date: 04 Apr 2018 04:04 AM pst
*/
sortByDescendingDemo(orders);
/* Returns
Order ID: 1, Quantity: 40, Order Date: Thu Feb 01 2018 01:01:01 GMT-0500 (Eastern Standard Time)
Order ID: 3, Quantity: 30, Order Date: Tue Apr 03 2018 03:03:03 GMT-0400 (Eastern Daylight Time)
Order ID: 2, Quantity: 20, Order Date: Fri Mar 02 2018 02:02:02 GMT-0500 (Eastern Standard Time)
Order ID: 5, Quantity: 20, Order Date: Tue Jun 05 2018 05:05:05 GMT-0400 (Eastern Daylight Time)
Order ID: 4, Quantity: 10, Order Date: Fri May 04 2018 04:04:04 GMT-0400 (Eastern Daylight Time)
*/

🔴 Closing Remark

In this article, I've shown examples of each LINQ method (approximate) equivalents in JavaScript.

Please feel free to leave a feedback on errors you might have spotted 😎.

The full source code and instructions on how to run them are on GitHub.