← Go Back

How to Implement LINQ methods in JavaScript - Part 5

Broken Post?Let me know

Photo by Jonas Vincent on Unsplash

I will cover common number aggregate methods in this article.

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

I've covered "min" and "max" in part 3 so I won't cover them again here.

🔴 Overview

In this article, I will cover following methods.

[table id=5 /]

And I will try to stick to using VanillaJS as I have so far.

The sample collections used in this article.

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

🔴 Examples

🔸 Sum

I will show you "Sum" demo first since "Average" is basically a sum divided by count.

private static void SumDemo(List<Order> orders)
{
var totalQuantities = orders.Sum(order => order.Quantity);
WriteLine($"SumDemo - Total Quantities: {totalQuantities}");
}
view raw SumDemo.cs hosted with ❤ by GitHub

Array.prototype.sum = function(propertySelector = obj => obj) {
const intialValue = 0;
return this.reduce((sum, obj) => sum + propertySelector(obj), intialValue);
};
function sumDemo(orders) {
const totalQuantities = orders.sum(order => order.quantity);
console.log(`sumDemo - Total Quantities: ${totalQuantities}`);
}
view raw sumDemo.js hosted with ❤ by GitHub

Results

// C#
==================== Sum DEMO - Sum All Quantities ====================
SumDemo - Total Quantities: 120
// JavaScript
==================== Reduce (LINQ 'Sum' Equivalent) DEMO - Sum All Quantities ====================
sumDemo - Total Quantities: 120
view raw SumDemo result hosted with ❤ by GitHub

Array.prototype.sum simply reduces each order quantity by summing it in the callback. Note 📝: It's exactly the same as the reduceDemo.

🔸 Average

Now let's get an average quantity ordered.

private static void AverageDemo(List<Order> orders)
{
var averageQuantity = orders.Average(order => order.Quantity);
var totalQuantities = orders.Sum(order => order.Quantity);
var count = orders.Count();
WriteLine($"Average Quantity: {totalQuantities} / {count} = {averageQuantity}");
}
view raw AverageDemo.cs hosted with ❤ by GitHub

Array.prototype.average = function(propertySelector = obj => obj) {
const intialValue = 0;
return (
this.reduce((sum, obj) => sum + propertySelector(obj), intialValue) /
this.length
);
};
function averageDemo(orders) {
var averageQuantity = orders.average(order => order.quantity);
var totalQuantities = orders.sum(order => order.quantity);
var count = orders.length;
WriteLine(
`Average Quantity: ${totalQuantities} / ${count} = ${averageQuantity}`
);
}
view raw averageDemo.js hosted with ❤ by GitHub

Results

// C#
==================== Avarage DEMO - Average Quantity ====================
Average Quantity: 120 / 5 = 24
// JavaScript
==================== Reduce (LINQ 'Average' Equivalent) DEMO - Average Quantity ====================
Average Quantity: 120 / 5 = 24
view raw Avarage Demo result hosted with ❤ by GitHub

The only difference here is that sum is divided by the order count to calculate an average.

🔸 Count

Count is overloaded in LINQ; One that simply returns a number of element in a sequence, and the other that accepts a predicate which lets you test each item.

I will implement the one with the predicate as the former is too simple.

private static void CountDemo(List<Order> orders)
{
var march = new DateTime(2018, 3, 1);
var ordersOnAndAfterMarch = orders.Where(order => order.OrderDate >= march);
PrintOrders(ordersOnAndAfterMarch, indentBy: 4);
var orderCountPlacedOnAndAfterMarch = orders.Count(order => order.OrderDate >= march);
WriteLine($"Total Orders Placed On and After March: {orderCountPlacedOnAndAfterMarch}");
}
view raw CountDemo.cs hosted with ❤ by GitHub

Array.prototype.count = function(predicate = obj => true) {
return this.filter(predicate).length;
};
function countDemo(orders) {
const march = new Date(2018, 3, 1);
const ordersOnAndAfterMarch = orders.filter(
order => order.orderDate >= march
);
printOrders(ordersOnAndAfterMarch, (indentBy = 4));
const orderCountPlacedOnAndAfterMarch = orders.count(
order => order.orderDate >= march
);
WriteLine(
`Total Orders Placed On and After March: ${orderCountPlacedOnAndAfterMarch}`
);
}
view raw countDemo.js hosted with ❤ by GitHub

Results

// C#
==================== Count DEMO - Count Orders Placed On and After March ====================
Order ID: 3, Quantity: 30, Order Date: 03 Mar 2018 03:03 AM pst
Order ID: 4, Quantity: 10, Order Date: 04 Apr 2018 04:04 AM pst
Order ID: 5, Quantity: 20, Order Date: 05 May 2018 05:05 AM pst
Total Orders Placed On and After March: 3
// JavaScript
==================== Filter (LINQ 'Count' Equivalent) DEMO - Count Orders Placed On and After March ====================
Order ID: 3, Quantity: 30, Order Date: Tue Apr 03 2018 03:03:03 GMT-0400 (Eastern Daylight Time)
Order ID: 4, Quantity: 10, Order Date: Fri May 04 2018 04:04:04 GMT-0400 (Eastern Daylight Time)
Order ID: 5, Quantity: 20, Order Date: Tue Jun 05 2018 05:05:05 GMT-0400 (Eastern Daylight Time)
Total Orders Placed On and After March: 3
view raw Count Demo Result hosted with ❤ by GitHub

The demo counts number of orders placed on and after March of 2018. Count without a predicate is same as array.length but filter is required for testing each element in an array.

🔴 Closing Remark

Sum, Average, and Count are often used and easy to implement (using for/each loops). I used reduce and filter to implement to make it look as similar to LINQ methods.

As always, I've not tested edge cases for Array prototypes so use the code at your own risk 😃. 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.