How to Implement LINQ methods in JavaScript - Part 5
Photo by Jonas Vincent on Unsplash
I will cover common number aggregate methods in this article.
Here are the methods covered so far.
- Part 1 〰️ Select, Aggregate, Where, OrderBy (Ascending, Descending)
- Part 2 〰️ Any, Distinct, Concat, SelectMany
- Part 3 〰️ Reverse, Zip, Min/Max
- Part 4 〰️ Union, Intersect, Except
- Part 5 〰️ Sum, Average, Count
- Part 6 〰️ First, Last, DefaultIfEmpty, Skip, Take
- Part 7 〰️ Empty, Repeat, Range
- 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)), | |
}; |
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) } | |
]; |
🔴 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}"); | |
} |
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}`); | |
} |
Results
// C# | |
==================== Sum DEMO - Sum All Quantities ==================== | |
SumDemo - Total Quantities: 120 | |
// JavaScript | |
==================== Reduce (LINQ 'Sum' Equivalent) DEMO - Sum All Quantities ==================== | |
sumDemo - Total Quantities: 120 |
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}"); | |
} |
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}` | |
); | |
} |
Results
// C# | |
==================== Avarage DEMO - Average Quantity ==================== | |
Average Quantity: 120 / 5 = 24 | |
// JavaScript | |
==================== Reduce (LINQ 'Average' Equivalent) DEMO - Average Quantity ==================== | |
Average Quantity: 120 / 5 = 24 |
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}"); | |
} |
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}` | |
); | |
} |
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 |
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.
Webmentions
Loading counts...