DEV Community

Reza Lavarian
Reza Lavarian

Posted on • Originally published at decodingweb.dev

JavaScript list (array) comprehension explained with examples

Update: This post was originally published on my blog decodingweb.dev, where you can read the latest version for a 💯 user experience. ~reza

List comprehension is a programming technique to create a new list based on an existing list. This quick guide explores three approaches to JavaScript list comprehension (a.k.a array comprehension).

Programmers use list or array comprehension for two reasons:

  1. To create a subset of a broad list (based on a set of conditions)
  2. To transform list items into new values and store them as a new list.

List comprehension is usually available as a language construct in many programming languages like Python or Perl. However, JavaScript has its own way of array comprehension.

For instance, if you have a list of email addresses and need to filter out Gmail accounts, here’s how you’d do it in Python:

emails = [
    # ...
]

gmail_accounts = [email for email in emails if email.endswith('gmail.com')]
Enter fullscreen mode Exit fullscreen mode

In JavaScript, however, there's no list (in this case, an array) comprehension construct, but there are ways to do that, thanks to Array.prototype.map(), Array.prototype.filter(), and the spread operator (...).

Let's see how.

List (array) comprehension in JavaScript

Based on your use cases, there are several approaches to list comprehension in JavaScript:

  1. Using Array.prototype.map()
  2. Using Array.prototype.filter()
  3. Using the for...of statement

1. Using Array.prototype.map()

If you want to transform every item in an array and return it as a new array, the Array.prototype.map() method is what you need.

Let's see some examples.

Example #1: Imagine we have a list of decimal values (e.g., prices) but only want the integer part (without the fraction part.)

const prices = [12.5, 45.34, 12.5, 9.5]
const pricesAsInt = prices.map(price => Math.trunc(price))

console.log(pricesAsInt)
// output: (4) [12, 45, 12, 9]
Enter fullscreen mode Exit fullscreen mode

In the above example, we called the map() method with an arrow function, which returns an integer (by using Math.trunc())

Example #2: Sometimes you have an array of objects and want to create a list of x from each object. Consider the following variable:

const persons = [
  { id: 238, name: Alice },
  { id: 874, name: Bob },
  { id: 421, name: Charlie }
]
Enter fullscreen mode Exit fullscreen mode

Imagine you want to generate an array of names from the above data structure. Here's how you'd do it with the map() method:

const names = persons.map(p => p.name)

console.log(names)
// output: (3) ['Alice', 'Bob', 'Charlie']
Enter fullscreen mode Exit fullscreen mode

In the above example, we pass the short arrow function p => p.name to the map() method. The variable p refers to an object on each iteration.

Example #3: Considering the persons array, imagine you need to add a new entry (active: true) to each object.

Here's one way of doing it:

const activePersons = persons.map(p => {
    p.active = true
    return p
})
Enter fullscreen mode Exit fullscreen mode

If you want an elegant single-line statement:

const activePersons = persons.map(p => ({ ...p, active: true }))
Enter fullscreen mode Exit fullscreen mode

Since we're using an arrow function without the curly braces, we wrapped the return value in a pair of parentheses. Otherwise, it would be mistaken for a function boundary by the parser. We used the spread operator (...p) to pack the existing entries alongside active: true as the new object.

As a rule of thumb, use the map() method whenever you want to transform list items without filtering them.

2. Using Array.prototype.filter()

If you want to create a subset of the original list. That's where the Array.prototype.filter() method comes in handy.

Let's see some examples.

Example #1: Imagine you have a list of emails but want to filter only Gmail accounts:

const emailAddresses = [
// ...
]

const gmailAccounts = emailAddress.filter(i => i.endsWidth('gmail.com'))
Enter fullscreen mode Exit fullscreen mode

The filter method accepts a callback function, which is run against every item in the array; If the callback function returns true, the item will be included in the new subset array.

In the above example, if the current item ends with gmail.com, the callback returns true, and the item is included in the final result.

Example #2: You can use the filter() method in conjunction with map().

For instance, after filtering the Gmail accounts, if you want to store them as objects in an array, you can do it like so:

const gmailAccounts = emailAddress.filter(i => i.endsWidth('gmail.com'))
    .map(i => ({ email: i }))
Enter fullscreen mode Exit fullscreen mode

As simple as that.

3. Using the for...of statement

The for...of statement allows you to iterate over a series of values from an iterable object (e.g., Array, String, TypedArray, Map, Set, NodeList, etc.).

If you want to reimplement the Gmail accounts example with the for...of statement, you could do it like so:

const emailAddresses = []
const gmailAccounts = []

for (email of emails) {
    if (!email.endsWith('gmail.com')) {
        return
    }

    gmailAccounts.push(email)
}
Enter fullscreen mode Exit fullscreen mode

In the above example, we iterate over the items and skip any email address not ending with gmail.com. Otherwise, we push it to the gmailAccounts array.

You could also use the Array.prototype.forEach() method to create a new list in the same way as the for...of statement.

Alright, I think it does it! I hope you found this quick guide helpful.

Thanks for reading.

Top comments (0)