Removing Elements from JavaScript Arrays

The JavaScript standard library is notoriously small. In fact, it is so small that the Arrayprototype doesn’t even define a method for removing a specific element from an array. ES2015 standardized some new array methods, but there’s still no remove function.

Because there’s no such built-in method, developers have to create their own version if they want to remove a specific array element. A common approach is to combine the indexOf and splice methods like this:

function remove(array, element) {
    const index = array.indexOf(element);
    array.splice(index, 1);
}

First, the index of the element in question is determined via indexOf. Second, splice is used to remove the array element at the given index. We only want to remove a single value, so we pass 1 as the second argument to splice, which specifies the delete count.

However, the remove function is buggy, as a simple example shows:

const vowels = ["a", "e", "i", "o", "u", "x"];
vowels.toString(); // "a,e,i,o,u,x"

// Let's remove "x" since it's not a vowel.
remove(vowels, "x");
vowels.toString(); // "a,e,i,o,u"

// What happens if we remove "x" again? Oops!
remove(vowels, "x");
vowels.toString(); // "a,e,i,o"

The remove function removes the last array element if the element to remove doesn’t occur within the array. In that case, indexOf returns the sentinel value -1. That value is passed to splice, which starts to count from the end of the array when it sees a negative index. -1 is the index of the last array element — not what was intended here.

Here’s a correct version of the remove function. The fix is to call splice if and only if indexOf didn’t return -1:

function remove(array, element) {
    const index = array.indexOf(element);
    
    if (index !== -1) {
        array.splice(index, 1);
    }
}

Look before you leap! Always check your indexOf return values.

Non-Mutating Element Removal

Removing an element from the given array is a mutating operation. The remove function changes the array that was passed to it, which might or might not be what the caller expected.

Another approach would be to implement a non-mutating element removal. Instead of directly modifying the input array, the remove function could return a new array that contains all elements except the specified one:

function remove(array, element) {
    return array.filter(e => e !== element);
}

const vowelsAndX = ["a", "e", "i", "o", "u", "x"];
const vowels = remove(vowelsAndX, "x");
vowels.toString(); // "a,e,i,o,u"

Note that this non-mutating version of remove works a little differently than its mutating sibling. It doesn’t only exclude the first occurence of the given element from the new array, but all of them.

Using ES2015 Sets

Yet another approach is to use the ES2015 Set data structure. It can be initialized with an array of values, and the Set prototype even provides a delete method for removing a specific value:

const vowels = new Set(["a", "e", "i", "o", "u", "x"]);
vowels.delete("x"); // true
vowels; // Set {"a", "e", "i", "o", "u"}

vowels.delete("x"); // false
vowels; // Set {"a", "e", "i", "o", "u"}

However, the semantics of sets are different from regular arrays. By definition, a set is a collection of unique values. Therefore, it never contains duplicates. If you need a collection that allows for duplicate values, sets are the wrong data structure.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: