Mark Brown Mark Brown - 7 months ago 87
Javascript Question

Move an array element from one array position to another

I'm having a hard time figuring out how to move an array element. For example, given the following:

var arr = [ 'a', 'b', 'c', 'd', 'e'];


How can I write a function to move
'd'
before
'b'
?

Or
'a'
after
'c'
?

After the move, the indices of the rest of the elements should be updated. This means in the first example after the move arr[0] would = 'a', arr[1] = 'd' arr[2] = 'b', arr[3] = 'c', arr[4] = 'e'

This seems like it should be pretty simple, but I can't wrap my head around it.

Answer

I had fairly good success with this function:

Array.prototype.move = function (old_index, new_index) {
    if (new_index >= this.length) {
        var k = new_index - this.length;
        while ((k--) + 1) {
            this.push(undefined);
        }
    }
    this.splice(new_index, 0, this.splice(old_index, 1)[0]);
    return this; // for testing purposes
};

Example code: [1, 2, 3].move(0, 1) gives [2, 1, 3].

Note that the last return is simply for testing purposes: splice performs operations on the array in-place, so a return is not necessary. By extension, this move is an in-place operation. If you want to avoid that and return a copy, use slice.

Stepping through the code:

  1. If new_index is greater than the length of the array, we want (I presume) to pad the array properly with new undefineds. This little snippet handles this by pushing undefined on the array until we have the proper length.
  2. Then, in this.splice(old_index, 1)[0], we splice out the old element. splice returns the element that was spliced out, but it's in an array. In our above example, this was [1]. So we take the first index of that array to get the raw 1 there.
  3. Then we use splice to insert this element in the new_index's place. Since we padded the array above if new_index > this.length, it will probably appear in the right place, unless they've done something strange like pass in a negative number.

A fancier version to account for negative indices:

Array.prototype.move = function (old_index, new_index) {
    while (old_index < 0) {
        old_index += this.length;
    }
    while (new_index < 0) {
        new_index += this.length;
    }
    if (new_index >= this.length) {
        var k = new_index - this.length;
        while ((k--) + 1) {
            this.push(undefined);
        }
    }
    this.splice(new_index, 0, this.splice(old_index, 1)[0]);
    return this; // for testing purposes
};

Which should account for things like [1, 2, 3, 4, 5].move(-1, -2) properly (move the last element to the second to last place). Result for that should be [1, 2, 3, 5, 4].

Either way, in your original question, you would do arr.move(0, 2) for a after c. For d before b, you would do arr.move(3, 1).

Comments