DEV Community

Cover image for JavaScript array methods for the C# dev
Brian Schroer
Brian Schroer

Posted on • Edited on

JavaScript array methods for the C# dev

A while ago, I gave a PowerPoint knowledge share presentation to a group of fellow C# developers at my office on JavaScript array methods and how they compare to the .NET LINQ methods that we’re familiar with.

I’ve found myself referencing that presentation since then, so I thought I’d put it somewhere accessible to me and others for future reference.

The headings below are links to the MDN documentation for the methods, so you can find more details and browser compatibility information there.

(These are not all of the many array methods, just the “LINQ-y” ones.)

array.length

const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

console.log(`There are ${months.length} months in your earth year`);
Enter fullscreen mode Exit fullscreen mode
There are 12 months in your earth year
Enter fullscreen mode Exit fullscreen mode

array.forEach

  • purpose: do something with each item in array
  • arguments: item, (index), (list)
  • “callback” responsibility: do something with item
  • returns: nothing (undefined)
  • C#/LINQ equivalent: List<T>.ForEach
const year = new Date().getFullYear();

const getDaysInMonth = month =>
  new Date(year, new Date(`1-${month}-${year}`).getMonth() + 1, 0).getDate();

months.forEach(m => console.log(`${m} has ${getDaysInMonth(m)} days in ${year}`));
Enter fullscreen mode Exit fullscreen mode
Jan has 31 days in 2019
Feb has 28 days in 2019
Mar has 31 days in 2019
Apr has 30 days in 2019
May has 31 days in 2019
Jun has 30 days in 2019
Jul has 31 days in 2019
Aug has 31 days in 2019
Sep has 30 days in 2019
Oct has 31 days in 2019
Nov has 30 days in 2019
Dec has 31 days in 2019
Enter fullscreen mode Exit fullscreen mode

forEach and many of the other functions discussed below require an “item” argument, but also accept optional “index” and “list” arguments.

Here’s an example of forEach(item, index):

months.forEach((m, i) => console.log(`${m} is month #${i + 1}`));
Enter fullscreen mode Exit fullscreen mode
Jan is month #1
Feb is month #2
Mar is month #3
Apr is month #4
May is month #5
Jun is month #6
Jul is month #7
Aug is month #8
Sep is month #9
Oct is month #10
Nov is month #11
Dec is month #12
Enter fullscreen mode Exit fullscreen mode

…and forEach(item, index, list):

months.forEach((m, i, list) => console.log(`${i + 1}) ${m} follows ${list.slice(0, i)}`));
Enter fullscreen mode Exit fullscreen mode
1) Jan follows
2) Feb follows Jan
3) Mar follows Jan,Feb
4) Apr follows Jan,Feb,Mar
5) May follows Jan,Feb,Mar,Apr
6) Jun follows Jan,Feb,Mar,Apr,May
7) Jul follows Jan,Feb,Mar,Apr,May,Jun
8) Aug follows Jan,Feb,Mar,Apr,May,Jun,Jul
9) Sep follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug
10) Oct follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep
11) Nov follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct
12) Dec follows Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov
Enter fullscreen mode Exit fullscreen mode

I’ll only show fn(item) examples for the remaining functions…

array.map

  • purpose: map array into a new array (of same or different types)
  • arguments: item, (index), (list)
  • “callback” responsibility: return new item for the new array
  • returns: new array
  • LINQ equivalent: IEnumerable<T>.Select
const firstDaysOfMonths = months.map(m => new Date(`1-${m}-${year}`));

firstDaysOfMonths.forEach(item => console.log(item));
Enter fullscreen mode Exit fullscreen mode
Mon Jan 01 2018 00:00:00 GMT-0600 (Central Standard Time)
Thu Feb 01 2018 00:00:00 GMT-0600 (Central Standard Time)
Thu Mar 01 2018 00:00:00 GMT-0600 (Central Standard Time)
Sun Apr 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Tue May 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Fri Jun 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Sun Jul 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Wed Aug 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Sat Sep 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Mon Oct 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Thu Nov 01 2018 00:00:00 GMT-0500 (Central Daylight Time)
Sat Dec 01 2018 00:00:00 GMT-0600 (Central Standard Time)
Enter fullscreen mode Exit fullscreen mode

array.filter

  • purpose: create a new array of items that match a predicate
  • arguments: item, (index), (list)
  • “callback” responsibility: predicate — return “truthy/falsy” value for item
  • returns: new filtered array
  • LINQ equivalent: IEnumerable<T>.Where
const monthsWith30Days = months.filter(m => getDaysInMonth(m) === 30);

console.log(monthsWith30Days);
Enter fullscreen mode Exit fullscreen mode
Apr,Jun,Sep,Nov
Enter fullscreen mode Exit fullscreen mode

array.reduce

  • purpose: determine something (e.g. sum, highest value) based on array items
  • arguments: result, item, (index), (list)
  • “callback” responsibility: based on previous result, what should be passed to next iteration?
  • returns: result of last iteration
  • LINQ equivalent: kind of like IEnumerable.Aggregate<T>
const daysInYear = months.reduce((result, m) => result + getDaysInMonth(m), /*initial value:*/ 0);

console.log(`There are ${daysInYear} days in ${year}`);
Enter fullscreen mode Exit fullscreen mode
There are 365 days in 2018
Enter fullscreen mode Exit fullscreen mode

array.reduceRight

…is like reduce, but it processes items from “right to left”. When I originally presented this material, I couldn’t think of a good use for reduceRight, but I saw an egghead.io Build Complex Functions with Function Composition in JavaScript lesson by Kyle Shevlin that showed a nifty use for it:

const shout = message => message.toUpperCase();
const exclaim = message => message + '!';
const repeat = message => `${message} ${message}`;

console.log(shout(repeat(exclaim('nested functions'))));

const compose = (...funcs) => x => funcs.reduceRight((result, func) => func(result), x);

const makeKnown = compose(
  shout,
  repeat,
  exclaim
);

console.log(makeKnown('composed function'));
Enter fullscreen mode Exit fullscreen mode
NESTED FUNCTIONS! NESTED FUNCTIONS!
COMPOSED FUNCTION! COMPOSED FUNCTION!
Enter fullscreen mode Exit fullscreen mode

array.some

  • purpose: Does one or more item match a predicate?
  • arguments: item, (index), (list)
  • “callback” responsibility: predicate — return “truthy/falsy” value for item
  • returns: true if any “truthy” responses (stops iterating after first “truthy” response)
  • LINQ equivalent: IEnumerable<T>.Any
const hasMonthStartingWithA = months.some(m => {
  console.log(`checking ${m}...`);
  return m[0] === 'A';
});

console.log(hasMonthStartingWithA);
Enter fullscreen mode Exit fullscreen mode
checking Jan...
checking Feb...
checking Mar...
checking Apr...
true
Enter fullscreen mode Exit fullscreen mode

array.every

  • purpose: Do all items match a predicate?
  • arguments: item, (index), (list)
  • “callback” responsibility: predicate — return “truthy/falsy” value for item
  • returns: true if all responses are “truthy” (stops iterating after “falsy” response)
  • LINQ equivalent: IEnumerable<T>.All
const hasNo30DayMonths = months.every(m => {
  const daysInMonth = getDaysInMonth(m);
  console.log(`${m} has ${daysInMonth} days`);
  return daysInMonth != 30;
});

console.log(hasNo30DayMonths);
Enter fullscreen mode Exit fullscreen mode
Jan has 31 days
Feb has 28 days
Mar has 31 days
Apr has 30 days
false
Enter fullscreen mode Exit fullscreen mode

array.find

  • purpose: find first item matching a predicate
  • arguments: item, (index), (list)
  • “callback” responsibility: predicate — return “truthy/falsy” value for item
  • returns first “truthy” item (or undefined, if none found — stops iterating after first “truthy response)
  • LINQ equivalent: IEnumerable<T>.FirstOrDefault
const first30DayMonth = months.find(m => getDaysInMonth(m) === 30);
const first40DayMonth = months.find(m => getDaysInMonth(m) === 40);
console.log(`1st 30 day month: ${first30DayMonth}`);
console.log(`1st 40 day month: ${first40DayMonth}`);
Enter fullscreen mode Exit fullscreen mode
1st 30 day month: Apr
1st 40 day month: undefined
Enter fullscreen mode Exit fullscreen mode

array.findIndex

…is like find, but it returns the found index instead of the item (-1 if not found):

const index30 = months.findIndex(m => getDaysInMonth(m) === 30);
const index40 = months.findIndex(m => getDaysInMonth(m) === 40);
console.log(`1st 30 day index: ${index30}`);
console.log(`1st 40 day index: ${index40}`);
Enter fullscreen mode Exit fullscreen mode
1st 30 day index: 3
1st 40 day index: -1
Enter fullscreen mode Exit fullscreen mode

array.includes

console.log(months.includes('Aug'));
console.log(months.includes('Dog'));
Enter fullscreen mode Exit fullscreen mode
true
false
Enter fullscreen mode Exit fullscreen mode

array.sort

  • purpose: sort array items
  • arguments: (compareFunction) — optional callback function that takes item1 and item2 and returns:

    • a negative number if item1 > item2
    • zero if item1 == item2
    • a positive number if item2 > item1

    (If compareFunction is omitted, a unicode comparison is performed, meaning everything is treated like a string)
    returns: the sorted array (not a new sorted array — it mutates the source array!)

  • LINQ equivalent: IEnumerable<T>.OrderBy

This is an older JavaScript function, from back when there were fewer “good parts”.

Notice that the months.sort() call updates the contents of the months variable:

  console.log(months);
  console.log(months.sort());
  console.log(months);
Enter fullscreen mode Exit fullscreen mode
  Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
  Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
  Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
Enter fullscreen mode Exit fullscreen mode

…and that without a compareFunction, numbers are sorted like strings:

  console.log(['1', '5', '10', '15', '20'].sort());
  console.log([1, 5, 10, 15, 20].sort());
Enter fullscreen mode Exit fullscreen mode
  1,10,15,20,5
  1,10,15,20,5
Enter fullscreen mode Exit fullscreen mode

If you need to create a new sorted array and leave the original array unsorted, you can first clone the array via the “slice” function or the spread (“…”) operator:

  console.log(months);
  console.log(months.slice().sort());
  console.log([...months].sort());
  console.log(months);
Enter fullscreen mode Exit fullscreen mode
  Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
  Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
  Apr,Aug,Dec,Feb,Jan,Jul,Jun,Mar,May,Nov,Oct,Sep
  Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Enter fullscreen mode Exit fullscreen mode

Here are examples of the sort method with a compareFunction callback:

  const sortedNumbers = [1, 5, 10, 15, 20].sort((num1, num2) => num1 - num2);
  console.log(sortedNumbers);

  const sortedByDaysInMonth = months.sort((m1, m2) => getDaysInMonth(m1) - getDaysInMonth(m2));

  console.log(sortedByDaysInMonth);
Enter fullscreen mode Exit fullscreen mode
  1,5,10,15,20
  Feb,Jun,Sep,Apr,Nov,Jul,Dec,Jan,Mar,Oct,May,Aug
Enter fullscreen mode Exit fullscreen mode

array.concat

  • purpose: merge two arrays into a new array
  • returns: new array
  • LINQ equivalent: IEnumerable<T>.Union
const months1 = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
const months2 = ['Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const months = months1.concat(months2);
console.log(months);
Enter fullscreen mode Exit fullscreen mode
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
Enter fullscreen mode Exit fullscreen mode

Top comments (0)