JavaScript list (array) comprehension explained with examples

Updated Sep 22, 2023 ⤳ 5 min read

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:

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

🎧 Debugging Jam

Calling all coders in need of a rhythm boost! Tune in to our 24/7 Lofi Coding Radio on YouTube, and let's code to the beat – subscribe for the ultimate coding groove!" Let the bug-hunting begin! 🎵💻🚀

24/7 lofi music radio banner, showing a young man working at his computer on a rainy autmn night with hot drink on the desk.

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')]

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]

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 }
]

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']

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

If you want an elegant single-line statement:


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

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

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

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

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.

Disclaimer: This post may contain affiliate links. I might receive a commission if a purchase is made. However, it doesn’t change the cost you’ll pay.

`