Reverse an array in place with me

In which I decide to get better at Javascript

As part of my attempt to better my Javascript skills, I have been working through Eloquent Javascript by Marijn Haverbeke. Chapter 4 is all about Arrays and Objects, and one of the exercises is to reverse an array in place. I thought it would be fun to present my solution and explain it, for anyone interested in following along.

I started by reversing an array without worrying about whether it was in place. To do so takes roughly three steps:

  1. initialize an empty array

  2. loop through the original array in reverse order and push each item into the empty array

  3. return the resulting array

Here's the Javascript code to do just that:

function reverseArray(arr) {
    let reversedArray = [];
    for (let i = arr.length-1; i>=0; i--) {
        reversedArray.push(arr[i]); 
    }
    return reversedArray; 
}

Note that to loop through the original array in reverse order, we start with i equal to arr.length-1 - this is because arrays are 0 indexed, so the length of the array will be one more than the actual index of the last item in the array.

Okay, but how do we do that in place? What does reversing an array in place even mean? When we reverse an array in place, we are changing the original array as we go, instead of adding values to a new array. So there will be no let reversedArray = [] or return reversedArray in our solution.

I found it helpful to visualize what I wanted to happen. So I pictured a kebab with 5 pieces of something tasty skewered onto it. If we wanted to reverse the order of the 5 pieces we'd slide a piece off of one end and then add it to the other end. That was my first approach.

function reverseArrayInPlace(arr) {
    let counter = 0; 
    while (counter <= arr.length -1) {
        let item = arr.pop()
        arr.unshift(item); 
        console.log(arr); // added for debugging after too long staring at screen in confusion
        counter++; 
    }
}

Welp. It didn't go so well. This approach yielded the following:

Screenshot of vscode terminal, yielding the following results: [ 5, 1, 2, 3, 4 ] [ 4, 5, 1, 2, 3 ] [ 3, 4, 5, 1, 2 ] [ 2, 3, 4, 5, 1 ] [ 1, 2, 3, 4, 5 ] [ 1, 2, 3, 4, 5 ]

You see, if you're removing and adding each piece on the kebab from the end and adding it to the beginning, eventually you'll just get back to your original kebab (or array) order. Didn't really think that one through. However, console.logging the array after each step in the loop definitely helped me uncover what was going awry!

It seemed my mental model of a kebab wasn't actually correct. Instead I needed to remove the last item and somehow insert it into - not the beginning every time - but the beginning only the first time. So the last item would go in the first slot, then the second to last item would go in the second slot, and the third to last item would go into the third slot, and so on.

And what Javascript method is good for inserting items into a particular slot in an array? splice! So I knew I could use pop to get the last item in my array, and I knew I'd need a counter to keep track of when I could stop popping and inserting elements. It remained to figure out how to use splice effectively.

I realized that the counter could keep track of how many times I'd looped through the array and how close it was to arr.length-1 but also could make use of that same value to tell splice where to insert its value. With that realization, I wrote the following code.

function reverseArrayInPlace(arr) {
    let counter = 0; 
    while (counter <= arr.length -1) {
        let item = arr.pop()
        arr.splice(counter, 0, item); 
        counter++; 
    }
}
  1. the function accepts an array

  2. the counter starts off at 0

  3. while the counter is less than or equal to the length of the array minus 1:

    1. we'll remove the last element in the array and store it in a variable (for ease of reading)

    2. then we'll insert the element into the correct slot, depending on what number counter is storing at the time

    3. finally we'll increase counter's value by one

  4. when counter equals the length of the array minus one we'll be done and break out of the while loop - that means the array is fully reversed

Try it for yourself!

let arrayValue = [1, 2, 3, 4, 5];
reverseArrayInPlace(arrayValue);
console.log(arrayValue); // → [5, 4, 3, 2, 1]