{ sung.codes }

by dance2die
Blog
← Go Back

How to Implement LINQ methods in JavaScript - Part 2

Broken Post?Let me know

Photo by Daniil Silantev on Unsplash

In the previous post, I've covered most used LINQ methods and implemented them in JavaScript.

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

In this post, I will cover following methods.

[table id=2 /]

And I will try to stick to using Vanilla JS.

The sample collection used in this part is the same as the previous one but I will list them again.

C#

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

⚡ NOTE ⚡ : In all of examples, WriteLine is used for printing result in console in both C# & JavaScript codes to make the code difference a bit easier to see.

In C#, it's statically imported as using static System.Console. In JavaScript, it's an alias of console.log declared as const WriteLine = console.log.

🔴 Examples

🔸 Any

some is equivalent to Any in LINQ. They do the same thing and both LINQ & JavaScript might as well have an alias to both "some" and "any" as TSQL does.

private static void AnyDemo(List<Order> orders)
{
var ordersMoreThanEqualToQuantity30Exists = orders.Any(order => order.Quantity >= 30);
WriteLine($"Are there orders with quantity great than and equal to 30? {ordersMoreThanEqualToQuantity30Exists}");
var ordersBeforeYear2018 = orders.Any(order => order.OrderDate.Year < 2018);
WriteLine($"Are there orders ordered before 2018? {ordersBeforeYear2018}");
var ordersWithIDGreaterThan100 = orders.Any(order => order.Id > 100);
WriteLine($"Do we have more than 100 Orders? {ordersWithIDGreaterThan100}");
}
view raw AnyDemo.cs hosted with ❤ by GitHub

function someDemo(orders) {
const ordersMoreThanEqualToQuantity30Exists = orders.some(
order => order.quantity >= 30
);
WriteLine(
`Are there orders with quantity great than and equal to 30? ${ordersMoreThanEqualToQuantity30Exists}`
);
const ordersBeforeYear2018 = orders.some(
order => order.orderDate.getFullYear() < 2018
);
WriteLine(`Are there orders ordered before 2018? ${ordersBeforeYear2018}`);
const ordersWithIDGreaterThan100 = orders.some(order => order.id > 100);
WriteLine(`Do we have more than 100 Orders? ${ordersWithIDGreaterThan100}`);
}
view raw someDemo.js hosted with ❤ by GitHub

Results

// result of "AnyDemo"
Are there orders with quantity great than and equal to 30? True
Are there orders ordered before 2018? False
Do we have more than 100 Orders? False
// result of "someDemo"
Are there orders with quantity great than and equal to 30? true
Are there orders ordered before 2018? false
Do we have more than 100 Orders? false

The only differences in JavaScript code are:

  1. some is used instead of Any
  2. Year is retrieved with a method call , getFullyear()
🔸 Distinct

There are some equivalent methods in jQuery (unique) or in Lodash (uniqby) but I will show you two implementations in Vanilla JS.

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

function distinctDemo1(orders) {
const distinctQuantityOrders = orders
.map(order => order.quantity)
.filter((quantity, index, self) => self.indexOf(quantity) === index);
distinctQuantityOrders.forEach(quantity =>
WriteLine(`Distinct Quantity: ${quantity}`)
);
}
/**
* An alternate method of implementing Distinct() LINQ method using new "Set" introduced in ES6 and the spread operator
*/
function distinctDemo2(orders) {
const distinctQuantityOrders = [
...new Set(orders.map(order => order.quantity))
];
distinctQuantityOrders.forEach(quantity =>
WriteLine(`Distinct Quantity: ${quantity}`)
);
}
view raw distinctDemos.js hosted with ❤ by GitHub

Results

The results for all three methods are the same.

Distinct Quantity: 40
Distinct Quantity: 20
Distinct Quantity: 30
Distinct Quantity: 10
view raw DistinctDemo result hosted with ❤ by GitHub

distinctDemo1 in JavaScript code uses filter to filter out records that does not show up as the first element in the list (Please refer to this StackOverflow question for more information for implementation details).

distinctDemo2 uses a Set object (sets by definition stores only unique values and is available from ES6) to store unique values in it, and uses a spread syntax to convert the Set object instance to an array (You could use another new ES6 addition, Array.from if you think it's not readable enough, as shown below).

const distinctQuantityOrders = [...new Set(orders.map(order => order.quantity))];
const distinctQuantityOrders = Array.from(new Set(orders.map(order => order.quantity)));

🔸 Concat

Thankfully 🙏, JavaScript has a method named concat, which does what LINQ version does. ⚠️ WARNING: Beware of super contrived example used in this demo.

private static void ConcatDemo(List<Order> orders)
{
var firstOrder = orders.Take(1);
var lastOrder = orders.TakeLast(1);
var firstAndLastOrders = firstOrder.Concat(lastOrder);
PrintOrders(firstAndLastOrders);
}
view raw ConcatDemo.cs hosted with ❤ by GitHub

function concatDemo(orders) {
const firstOrder = [orders[0]];
const lastOrder = [[...orders].pop()];
const firstAndLastOrders = firstOrder.concat(lastOrder);
printOrders(firstAndLastOrders);
}
view raw concatDemo.js hosted with ❤ by GitHub

Results

Order ID: 1, Quantity: 40, Order Date: Thu Feb 01 2018 01:01:01 GMT-0500 (Eastern Standard Time)
Order ID: 5, Quantity: 20, Order Date: Tue Jun 05 2018 05:05:05 GMT-0400 (Eastern Daylight Time)

Syntax is exactly the same 😄(except capitalization), so moving right along to the next example⤵️, SelectMany.

🔸 SelectMany

This example does exactly the same thing (and just as contrived) as Concat does but wanted to share a different way you can implement it in JavaScript.

private static void SelectManyDemo(List<Order> orders)
{
var firstOrder = orders.Take(1);
var lastOrder = orders.TakeLast(1);
var firstAndLastOrders = new [] {firstOrder, lastOrder}.SelectMany(order => order);
PrintOrders(firstAndLastOrders);
}
view raw SelectManyDemo.cs hosted with ❤ by GitHub

function spreadDemo(orders) {
const firstOrder = [orders[0]];
const lastOrder = [[...orders].pop()];
// spread operator "..." on each array does the same thing as "SelectMany" in LINQ.
const firstAndLastOrders = [...firstOrder, ...lastOrder];
printOrders(firstAndLastOrders);
}
view raw spreadDemo.js hosted with ❤ by GitHub

Results

As you can see, the result is exactly the same as the one in Concat demo.

Order ID: 1, Quantity: 40, Order Date: Thu Feb 01 2018 01:01:01 GMT-0500 (Eastern Standard Time)
Order ID: 5, Quantity: 20, Order Date: Tue Jun 05 2018 05:05:05 GMT-0400 (Eastern Daylight Time)

SelectMany basically flattens multiple collections into a single one, while Spread syntax in ES6 is used to flatten all arrays into a single one.

🔴 Closing Remark

I have selected frequently used LINQ methods (at least for me that is) and shown you the JavaScript implementations. I hope you found the mapping between LINQ to JavaScript code useful. Please let me know should you find any errors or improvements I can make to the codes.

The full source code and instructions on how to run them are on GitHub. (Same as the first part as demos are added onto existing source code)