JavaScript array methods for the C# dev
Tags: javascript, csharp
Published: 2019-08-24 15:06:16

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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/length)

- purpose: get array size
- returns: number
- LINQ equivalent: [IEnumerable<_T_>.Count](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.count?view=netframework-4.8) (or [Array.Length](https://docs.microsoft.com/en-us/dotnet/api/system.array.length?view=netframework-4.8))

```javascript
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`);
```

```
There are 12 months in your earth year
```

### [array.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.foreach?view=netframework-4.8)

```javascript
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}`));
```

```
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
```

**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)**:

```javascript
months.forEach((m, i) => console.log(`${m} is month #${i + 1}`));
```

```
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
```

…and **forEach(item, index, list)**:

```javascript
months.forEach((m, i, list) => console.log(`${i + 1}) ${m} follows ${list.slice(0, i)}`));
```

```
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
```

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

### [array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select?view=netframework-4.8)

```javascript
const firstDaysOfMonths = months.map(m => new Date(`1-${m}-${year}`));

firstDaysOfMonths.forEach(item => console.log(item));
```

```
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)
```

### [array.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where?view=netframework-4.8)

```javascript
const monthsWith30Days = months.filter(m => getDaysInMonth(m) === 30);

console.log(monthsWith30Days);
```

```
Apr,Jun,Sep,Nov
```

### [array.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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_>](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.aggregate?view=netframework-4.8)

```javascript
const daysInYear = months.reduce((result, m) => result + getDaysInMonth(m), /*initial value:*/ 0);

console.log(`There are ${daysInYear} days in ${year}`);
```

```
There are 365 days in 2018
```

### [array.reduceRight](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://egghead.io/lessons/javascript-build-complex-functions-with-function-composition-in-javascript) lesson by Kyle Shevlin that showed a nifty use for it:

```javascript
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'));
```

```
NESTED FUNCTIONS! NESTED FUNCTIONS!
COMPOSED FUNCTION! COMPOSED FUNCTION!
```

### [array.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.any?view=netframework-4.8)

```javascript
const hasMonthStartingWithA = months.some(m => {
  console.log(`checking ${m}...`);
  return m[0] === 'A';
});

console.log(hasMonthStartingWithA);
```

```
checking Jan...
checking Feb...
checking Mar...
checking Apr...
true
```

### [array.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.all?view=netframework-4.8)

```javascript
const hasNo30DayMonths = months.every(m => {
  const daysInMonth = getDaysInMonth(m);
  console.log(`${m} has ${daysInMonth} days`);
  return daysInMonth != 30;
});

console.log(hasNo30DayMonths);
```

```
Jan has 31 days
Feb has 28 days
Mar has 31 days
Apr has 30 days
false
```

### [array.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.firstordefault?view=netframework-4.8)

```javascript
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}`);
```

```
1st 30 day month: Apr
1st 40 day month: undefined
```

### [array.findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)

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

```javascript
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}`);
```

```
1st 30 day index: 3
1st 40 day index: -1
```

### [array.includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes)

- purpose: does array include specified entry?
- returns: bool
- LINQ equivalent: [IEnumerable<_T_>.Contains](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.contains?view=netframework-4.8)

```javascript
console.log(months.includes('Aug'));
console.log(months.includes('Dog'));
```

```
true
false
```

### [array.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/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](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.orderby?view=netframework-4.8)

  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:

  ```javascript
  console.log(months);
  console.log(months.sort());
  console.log(months);
  ```

  ```
  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
  ```

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

  ```javascript
  console.log(['1', '5', '10', '15', '20'].sort());
  console.log([1, 5, 10, 15, 20].sort());
  ```

  ```
  1,10,15,20,5
  1,10,15,20,5
  ```

  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:

  ```javascript
  console.log(months);
  console.log(months.slice().sort());
  console.log([...months].sort());
  console.log(months);
  ```

  ```
  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
  ```

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

  ```javascript
  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);
  ```

  ```
  1,5,10,15,20
  Feb,Jun,Sep,Apr,Nov,Jul,Dec,Jan,Mar,Oct,May,Aug
  ```

## [array.concat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat)

- purpose: merge two arrays into a new array
- returns: new array
- LINQ equivalent: [IEnumerable<_T_>.Union](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.union?view=netframework-4.8)

```javascript
const months1 = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'];
const months2 = ['Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const months = months1.concat(months2);
console.log(months);
```

```
Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
```