749

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

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

How can I write a function to move the element 'd' to the left of 'b' ?

Or 'a' to the right of 'c'?

After moving the elements, the indexes of the rest of the elements should be updated. The resulting array would be:

array = ['a', 'd', 'b', 'c', 'e']

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

Gass
  • 7,536
  • 3
  • 37
  • 41
Mark Brown
  • 12,026
  • 8
  • 27
  • 32
  • using ES6 `const changeValuePosition = (arr, init, target) => {[arr[init],arr[target]] = [arr[target],arr[init]]; return arr}` – principiorum May 18 '20 at 03:24
  • 5
    That just swaps the elements at `init` and `target`. –  May 24 '20 at 18:49
  • @user4945014 It's not just swapping. If a swap occurs, the OP would get array = ['a', 'd', 'c', 'b', 'e'], which would mean 'c' and 'b' would be in the wrong order. An insert and shift as he's looking for will keep 'b' and 'c' in the same order. – John May 01 '22 at 17:41

48 Answers48

876

If you'd like a version on npm, array-move is the closest to this answer, although it's not the same implementation. See its usage section for more details. The previous version of this answer (that modified Array.prototype.move) can be found on npm at array.prototype.move.


I had fairly good success with this function:

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

// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1)); 

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 arr.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 > arr.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:

function array_move(arr, old_index, new_index) {
    while (old_index < 0) {
        old_index += arr.length;
    }
    while (new_index < 0) {
        new_index += arr.length;
    }
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing purposes
};
    
// returns [1, 3, 2]
console.log(array_move([1, 2, 3], -1, -2));

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

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

Reid
  • 18,959
  • 5
  • 37
  • 37
  • 27
    This works perfectly! And your explanation is very clear. Thanks for taking the time to write this up. – Mark Brown Mar 15 '11 at 04:31
  • 18
    You shouldn't manipulate Object and Array prototypes, it causes problems when iterating elements. – burak emre Mar 19 '13 at 01:38
  • 10
    @burakemre: I think that conclusion is not so clearly reached. Most good JS programmers (and most popular libraries) will use a `.hasOwnProperty` check when iterating with things like for..in, especially with libraries like Prototype and MooTools which modify prototypes. Anyway, I didn't feel it was a particularly important issue in a relatively limited example like this, and there is a nice split in the community over whether or not prototype modification is a good idea. Normally, iteration problems are the least concern, though. – Reid Mar 19 '13 at 03:24
  • 3
    There is no need for the loop in step 1, you can simply use `this[new_index] = undefined;` within the `if` block. As Javascript arrays are sparse this will extend the array size to include the new_index for the `.splice` to work but without needing to create any intervening elements. – Rebecka Jul 03 '15 at 11:23
  • 3
    @Michael: Good point - but doing `this[new_index] = undefined` will actually put an `undefined` in the array slot *before* the correct index. (E.g., `[1,2,3].move(0,10)` will have `1` in slot 10 and `undefined` in slot 9.) Rather, if sparseness is OK, we could do `this[new_index] = this.splice(old_index, 1)[0]` without the other splice call (make it an if/else instead). – Reid Jul 03 '15 at 13:37
  • 1
    I've added Reid's code (the "fancier" version) as an npm package at https://www.npmjs.com/package/array.prototype.move. I've credited Reid appropriately there, I hope. Please let me know if not. – ChillyPenguin Mar 09 '16 at 09:42
  • 4
    PLEASE PLEASE don't add this to the prototype. When the TC39 wants to add it natively to JavaScript they will have to use a different, awkward name because of people doing this. – jayphelps Jan 05 '17 at 03:46
  • 3
    I've updated the post so that it doesn't modify the array prototype. Looking back, I recognize that modifying the prototype was on shaky ground at best in 2011, and now that we're in 2018, it's high time I changed the post. – Reid Feb 03 '18 at 21:35
  • 1
    So it seems to work with just this: ``function array_move(arr: any[], oldIndex: number, newIndex: number) { arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]); return arr; }`` Why are we pushing falsy values? – Crystal May 13 '19 at 22:04
  • `Array.splice()` already handles negative numbers. There's no need for the second section of code. – Caveman Nov 14 '20 at 13:34
  • After some testing i get some null item added to the original array – Photonic Dec 17 '21 at 07:33
  • 2
    Actually I see a problem here: if I call `array_move([0, 1, 2, 3, 4], 3, 1)`, then an item with index `3` is moved at the position before an item with index `1`, it works fine. However by calling `array_move([0, 1, 2, 3, 4], 1, 3)` I expect the same behavior - that an item with index `1` is moved BEFORE an item with index `3` - so the expected result would be `[0, 2, 1, 3, 4]`, which is not. Correct code should imo be `arr.splice(new_index > old_index ? new_index - 1 : new_index, 0, arr.splice(old_index, 1)[0]);` – hejdav Sep 10 '22 at 16:37
  • Don't use this solution, there is much better one without creating new arrays from @Merc. – Alexander Danilov Jun 27 '23 at 10:55
515

I like this way. It's concise and it works.

function arraymove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
}

Note: always remember to check your array bounds.

Run Snippet in jsFiddle

Steak Overflow
  • 7,041
  • 1
  • 37
  • 59
  • 54
    Since Array.splice returns the removed value(s) in a new Array, you can write it as a one liner... arr.splice(index + 1, 0, arr.splice(index, 1)[0]); – Eric Rini Feb 03 '14 at 19:20
  • 135
    Personally I prefer the 3 line code. It's easier to understand: Get a copy of the element; remove it from the array; insert it in a new position. The one liner is shorter but not so clear for other people to understand... – Philipp Jan 03 '18 at 22:15
  • 9
    Short and simple code. But it's 2019!!, Create a clone of the array and return it instead of mutating the array. This will make your function "arraymove" comply to functional programming standards – SamwellTarly Aug 04 '19 at 16:10
  • 3
    Functional programming is great in many situations but not everything needs to, nor has to comply to functional programming standards. If you're a pure functions warrior this can still be useful locally. It depends by how fine grain your functional methods are. – Steak Overflow Jul 03 '20 at 10:07
  • It's 2020. Please don't mutate array inside a function. – refaelio Dec 03 '20 at 15:12
  • 3
    Care explaining why not? – Steak Overflow Dec 03 '20 at 15:25
  • 12
    I would have never imagine that for some people, after 2019, mutating an array in place would have become out of fashion. Perfectly legit answer, +1. – Luca Fagioli Mar 27 '21 at 12:16
  • 24
    It's 2021. There are still cases where copying is totally inappropriate for memory/performance reasons. Pure functions should be the default, but it shouldn't be dogma. – mindplay.dk Apr 10 '21 at 14:14
  • 3
    2022 here - recently had to work with massive datasets in javascript and I can tell you now, cloning to make a simple change or using array functions is not a good idea at all. I hate this mentality of "having" to make everything immutable. Javascript wasn't designed to be immutable, if it was, it'd be efficient to program in this manner. – user678415 Aug 09 '22 at 11:51
  • 3
    @SamwellTarly 1979-2022 here: one size does not fit all; horses for courses -- OP did not specify the need for a pure function, or that he was working with a dataset whose size would make it practical. – Lee Goddard Sep 26 '22 at 08:17
  • The key is in understanding how Array. splice work. The first ```slice``` removed the value we want to move and then the second ```slice``` pushed that value we want to move to the index we want to move it. That operation will move other values by the right, further right. – Henry Obiaraije Mar 21 '23 at 16:46
  • 1
    Everybody talking about not mutating the array and nobody noticed that if `toIndex` is greater than `fromIndex` it needs to be decremented?? – Ricardo Jun 20 '23 at 10:08
  • @Ricardo Thank you, I thought I was going crazy looking at this thinking it shouldn't work. Trying it and seeing that it doesn't work. Am I crazy? I feel like I'm crazy. – S. Buda Aug 22 '23 at 17:57
  • @Ricardo decrement what? Have you tried the snippet? It tests all permutations of couples ([0..5], [0..5]). If you look at the console you'll see all correct results. – Steak Overflow Aug 28 '23 at 11:24
330

Here's a one liner I found on JSPerf....

Array.prototype.move = function(from, to) {
    this.splice(to, 0, this.splice(from, 1)[0]);
};

which is awesome to read, but if you want performance (in small data sets) try...

 Array.prototype.move2 = function(pos1, pos2) {
    // local variables
    var i, tmp;
    // cast input parameters to integers
    pos1 = parseInt(pos1, 10);
    pos2 = parseInt(pos2, 10);
    // if positions are different and inside array
    if (pos1 !== pos2 && 0 <= pos1 && pos1 <= this.length && 0 <= pos2 && pos2 <= this.length) {
      // save element from position 1
      tmp = this[pos1];
      // move element down and shift other elements up
      if (pos1 < pos2) {
        for (i = pos1; i < pos2; i++) {
          this[i] = this[i + 1];
        }
      }
      // move element up and shift other elements down
      else {
        for (i = pos1; i > pos2; i--) {
          this[i] = this[i - 1];
        }
      }
      // put element from position 1 to destination
      this[pos2] = tmp;
    }
  }

I can't take any credit, it should all go to Richard Scarrott. It beats the splice based method for smaller data sets in this performance test. It is however significantly slower on larger data sets as Darwayne points out.

tagurit
  • 494
  • 5
  • 13
digiguru
  • 12,724
  • 20
  • 61
  • 87
  • This move2 method is nice, as it allows for moving the an array element either up or down the array. I ran into problems, with some of the other solutions when moving array elements to the right. – Benjen Jun 01 '12 at 02:04
  • 2
    Your more performant solution is slower on large datasets. http://jsperf.com/array-prototype-move/8 – Darwayne May 20 '13 at 11:55
  • 59
    This seems like a really silly tradeof. Performance on small data sets is a negligible gain, but loss on large data sets is a significant loss. Your net exchange is negative. – Kyeotic Nov 06 '13 at 02:30
  • 1
    The one-liner is nice, but does not handle moving elements beyond the end of the array. – Reid Mar 01 '16 at 18:53
  • 3
    @Reid That wasn't a requirement. IMO it is okay to assume that the length of the array doesn't get modified. – robsch Mar 08 '16 at 10:57
  • It should go to note array.prototype.move is no longer supported. – NicholasByDesign Feb 05 '17 at 06:34
  • 4
    One line solution need to handle two situations: `from >= to ? this.splice(to, 0, this.splice(from, 1)[0]) : this.splice(to - 1, 0, this.splice(from, 1)[0]);` – Rob Lao Jul 07 '17 at 01:42
  • 23
    Please never modify builtin prototypes, ever. http://www.nczonline.net/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/ – LJHarb Jan 04 '18 at 03:17
  • 2
    do not add things in the prototype, guys – Paul Melero Mar 27 '18 at 13:00
  • I know that this is old, but I cant move the element at first position to the last position with the 1liner - Any idea? – Celebrombore Jun 11 '20 at 15:14
  • great solution, and I believe it is a right use case for adding it as a prototype. Big like! – Kostanos Jun 23 '22 at 08:23
47

The splice() method adds/removes items to/from an array, and returns the removed item(s).

Note: This method changes the original array. /w3schools/

Array.prototype.move = function(from,to){
  this.splice(to,0,this.splice(from,1)[0]);
  return this;
};

var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(3,1);//["a", "d", "b", "c", "e"]


var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(0,2);//["b", "c", "a", "d", "e"]

as the function is chainable this works too:

alert(arr.move(0,2).join(','));

demo here

Community
  • 1
  • 1
  • 6
    See other comments about this: it's a bad idea to modify built-in prototypes like Array and Object. You will break things. – geoidesic Jan 29 '18 at 19:10
37

My 2c. Easy to read, it works, it's fast, it doesn't create new arrays.

function move(array, from, to) {
  if( to === from ) return array;

  var target = array[from];                         
  var increment = to < from ? -1 : 1;

  for(var k = from; k != to; k += increment){
    array[k] = array[k + increment];
  }
  array[to] = target;
  return array;
}
Merc
  • 16,277
  • 18
  • 79
  • 122
25

Here is my one liner ES6 solution with an optional parameter on.

if (typeof Array.prototype.move === "undefined") {
  Array.prototype.move = function(from, to, on = 1) {
    this.splice(to, 0, ...this.splice(from, on))
  }
}

Adaptation of the first solution proposed by digiguru

The parameter on is the number of element starting from from you want to move.

Here is a chainable variation of this:

if (typeof Array.prototype.move === "undefined") {
  Array.prototype.move = function(from, to, on = 1) {
    return this.splice(to, 0, ...this.splice(from, on)), this
  }
}

[3, 4, 5, 1, 2].move(3, 0, 2) // => [1, 2, 3, 4, 5]

If you'd like to avoid prototype pollution, here's a stand-alone function:

function move(array, from, to, on = 1) {
  return array.splice(to, 0, ...array.splice(from, on)), array
}

move([3, 4, 5, 1, 2], 3, 0, 2) // => [1, 2, 3, 4, 5]

And finally, here's a pure function that doesn't mutate the original array:

function moved(array, from, to, on = 1) {
  return array = array.slice(), array.splice(to, 0, ...array.splice(from, on)), array
}

This should cover basically every variation seen in every other answer.

mindplay.dk
  • 7,085
  • 3
  • 44
  • 54
Elie Teyssedou
  • 749
  • 1
  • 7
  • 19
  • 2
    The solution is fine. However, when you expand a prototype you shouldn't use arrow function because in this case 'this' is not an array instance but for example Window object. – wawka Jun 23 '18 at 06:40
  • 2
    This is my favorite answer - modern, concise and simple. I added a chainable variation, to be more consistent with the standard Array methods. Some folks are going to take issue with prototype pollution, so I added a stand-alone function as well. Finally, some use-cases require a pure function, as opposed to in-place manipulation, so I added that as well. – mindplay.dk Apr 11 '21 at 09:32
  • 4
    I couldn't understand the last pure function. Is that statement comma separated? How does it work? – batbrain9392 Aug 06 '21 at 15:23
  • 2
    @batbrain9392 - Check this question: https://stackoverflow.com/q/10284536/1914985 – Chique Sep 09 '21 at 22:55
21

Got this idea from @Reid of pushing something in the place of the item that is supposed to be moved to keep the array size constant. That does simplify calculations. Also, pushing an empty object has the added benefits of being able to search for it uniquely later on. This works because two objects are not equal until they are referring to the same object.

({}) == ({}); // false

So here's the function which takes in the source array, and the source, destination indexes. You could add it to the Array.prototype if needed.

function moveObjectAtIndex(array, sourceIndex, destIndex) {
    var placeholder = {};
    // remove the object from its initial position and
    // plant the placeholder object in its place to
    // keep the array length constant
    var objectToMove = array.splice(sourceIndex, 1, placeholder)[0];
    // place the object in the desired position
    array.splice(destIndex, 0, objectToMove);
    // take out the temporary object
    array.splice(array.indexOf(placeholder), 1);
}
Anurag
  • 140,337
  • 36
  • 221
  • 257
16

This is based on @Reid's solution. Except:

  • I'm not changing the Array prototype.
  • Moving an item out of bounds to the right does not create undefined items, it just moves the item to the right-most position.

Function:

function move(array, oldIndex, newIndex) {
    if (newIndex >= array.length) {
        newIndex = array.length - 1;
    }
    array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
    return array;
}

Unit tests:

describe('ArrayHelper', function () {
    it('Move right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 0, 1);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    })
    it('Move left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 0);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, -2);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 4);
        assert.equal(array[0], 1);
        assert.equal(array[1], 3);
        assert.equal(array[2], 2);
    });
});
Andre Pena
  • 56,650
  • 48
  • 196
  • 243
  • 1
    this is wrong, if you insert a post position, the index will change since you have remove the item – Yao Zhao May 13 '16 at 13:14
  • Thank you. I wanted to remove an item from an array without leaving a null element (which occured when using splice(indexToRemove). I used your method to move the item I wanted to remove to the end of the array, and then used the pop() method to remove. – Luke Schoen Jul 09 '16 at 13:12
  • liked "move the item to the right-most position" feature, useful for my case. thx – bFunc Aug 20 '18 at 13:17
10

You can implement some basic calculus and create a universal function for moving array elements from one position to the other.

For JavaScript it looks like this:

function magicFunction (targetArray, indexFrom, indexTo) { 

    targetElement = targetArray[indexFrom]; 
    magicIncrement = (indexTo - indexFrom) / Math.abs (indexTo - indexFrom); 

    for (Element = indexFrom; Element != indexTo; Element += magicIncrement){ 
        targetArray[Element] = targetArray[Element + magicIncrement]; 
    } 

    targetArray[indexTo] = targetElement; 

}

Check out "moving array elements" at "Gloommatter" for detailed explanation.

https://web.archive.org/web/20121105042534/http://www.gloommatter.com:80/DDesign/programming/moving-any-array-elements-universal-function.html

tagurit
  • 494
  • 5
  • 13
Andrea
  • 107
  • 1
  • 2
9

I've implemented an immutable ECMAScript 6 solution based off of @Merc's answer over here:

const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
  if (fromIndex === toIndex) return array;

  const newArray = [...array];

  const target = newArray[fromIndex];
  const inc = toIndex < fromIndex ? -1 : 1;

  for (let i = fromIndex; i !== toIndex; i += inc) {
    newArray[i] = newArray[i + inc];
  }

  newArray[toIndex] = target;

  return newArray;
};

The variable names can be shortened, just used long ones so that the code can explain itself.

Barry Michael Doyle
  • 9,333
  • 30
  • 83
  • 143
  • definitely a better answer, mutations creates side effects – Matt Lo Oct 19 '18 at 04:30
  • 1
    Out of curiosity, why not just return `array` immediately if `fromIndex === toIndex`, and only create the `newArray` if it's not the case? Immutability doesn't mean that one fresh copy must be created per function call even when there's no change. Just asking b/c the motive for the increased length of this function (relative to splice based one-liners) is performance, and `fromIndex` may well often equal `toIndex`, depending on the usage. – Robert Monfera Nov 01 '18 at 19:49
6

One approach would be to create a new array with the pieces in the order you want, using the slice method.

Example

var arr = [ 'a', 'b', 'c', 'd', 'e'];
var arr2 = arr.slice(0,1).concat( ['d'] ).concat( arr.slice(2,4) ).concat( arr.slice(4) );
  • arr.slice(0,1) gives you ['a']
  • arr.slice(2,4) gives you ['b', 'c']
  • arr.slice(4) gives you ['e']
Jared Updike
  • 7,165
  • 8
  • 46
  • 72
  • 1
    You do realize that your `arr2` ends up being a string due to the concatenation operations, right? :) It ends up being `"adc,de"`. – Ken Franqueiro Mar 15 '11 at 02:07
6

Another pure JS variant using ES6 array spread operator with no mutation

const reorder = (array, sourceIndex, destinationIndex) => {
 const smallerIndex = Math.min(sourceIndex, destinationIndex);
 const largerIndex = Math.max(sourceIndex, destinationIndex);

 return [
  ...array.slice(0, smallerIndex),
  ...(sourceIndex < destinationIndex
   ? array.slice(smallerIndex + 1, largerIndex + 1)
   : []),
  array[sourceIndex],
  ...(sourceIndex > destinationIndex
   ? array.slice(smallerIndex, largerIndex)
   : []),
  ...array.slice(largerIndex + 1),
 ];
}

// returns ['a', 'c', 'd', 'e', 'b', 'f']
console.log(reorder(['a', 'b', 'c', 'd', 'e', 'f'], 1, 4))
      
 
abr
  • 169
  • 2
  • 7
  • I personally loved this and with the next search will run across this again ... so adding my own personalized implementation ... const swapIndex = (array, from, to) => ( from < to ? [...array.slice(0, from), ...array.slice(from + 1, to + 1), array[from], ...array.slice(to + 1)] : [...array.slice(0, to), array[from], ...array.slice(to, from), ...array.slice(from + 1)] ); – Dudley Craig Oct 14 '21 at 16:30
  • This answer should be higher thanks to the purity. – mjrdnk Feb 07 '23 at 22:54
  • This answer is amazing. Non-mutative, and it does boundary checks elegantly. However, there's a bug. If you define a sourceIndex that does not exist in the array, you end up with an array 1 size larger than the original that includes an undefined value. Eg [1,2,3,4,5] becomes [undefined,1,2,3,4,5] – Hybrid web dev Feb 21 '23 at 08:46
5

I needed an immutable move method (one that didn't change the original array), so I adapted @Reid's accepted answer to simply use Object.assign to create a copy of the array before doing the splice.

Array.prototype.immutableMove = function (old_index, new_index) {
  var copy = Object.assign([], this);
  if (new_index >= copy.length) {
      var k = new_index - copy.length;
      while ((k--) + 1) {
          copy.push(undefined);
      }
  }
  copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
  return copy;
};

Here is a jsfiddle showing it in action.

Javid Jamae
  • 8,741
  • 4
  • 47
  • 62
5

The splice method of Array might help: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

Just keep in mind it might be relatively expensive since it has to actively re-index the array.

Ken Franqueiro
  • 10,559
  • 2
  • 23
  • 40
  • Yep, but as soon as I perform the splice, the array indices are updated, which makes it difficult for me to figure out where to place the element that I just removed. Especially since I need the function to be able to handle moves in both directions. – Mark Brown Mar 15 '11 at 02:12
  • @Mark: don't splice the string and save it into the same variable, make a new string and splice that. See my answer below. – Jared Updike Mar 15 '11 at 16:04
5

One approach would be to use splice() to remove the item from the array and then by using splice() method again, insert the removed item into the target index.

const array = ['a', 'b', 'c', 'd', 'e']

const newArray = moveItem(array, 3, 1) // move element from index 3 to index 1

function moveItem(arr, fromIndex, toIndex){
  let itemRemoved = arr.splice(fromIndex, 1) // assign the removed item as an array
  arr.splice(toIndex, 0, itemRemoved[0]) // insert itemRemoved into the target index
  return arr
}

console.log(newArray)

You can find a short explanation of splice() here

Gass
  • 7,536
  • 3
  • 37
  • 41
5

TypeScript Version

Copied from @Merc's answer. I like that one best because it is not creating new arrays and modifies the array in place. All I did was update to ES6 and add the types.

export function moveItemInArray<T>(workArray: T[], fromIndex: number, toIndex: number): T[] {
    if (toIndex === fromIndex) {
        return workArray;
    }
    const target = workArray[fromIndex];
    const increment = toIndex < fromIndex ? -1 : 1;

    for (let k = fromIndex; k !== toIndex; k += increment) {
        workArray[k] = workArray[k + increment];
    }
    workArray[toIndex] = target;
    return workArray;
}
FirstVertex
  • 3,657
  • 34
  • 33
5

In 2022, this typescript utility will work along with a unit test.

export const arrayMove = <T>(arr: T[], fromIndex: number, toIndex: number) => {
  const newArr = [...arr];
  newArr.splice(toIndex, 0, newArr.splice(fromIndex, 1)[0]);
  return newArr;
};

const testArray = ['1', '2', '3', '4'];

describe('arrayMove', () => {
  it('should move array item to toIndex', () => {
    expect(arrayMove(testArray, 2, 0)).toEqual(['3', '1', '2', '4']);
    expect(arrayMove(testArray, 3, 1)).toEqual(['1', '4', '2', '3']);
    expect(arrayMove(testArray, 1, 2)).toEqual(['1', '3', '2', '4']);
    expect(arrayMove(testArray, 0, 2)).toEqual(['2', '3', '1', '4']);
  });
});
kinoli
  • 109
  • 2
  • 5
4
    Array.prototype.moveUp = function (value, by) {
        var index = this.indexOf(value),
            newPos = index - (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos < 0)
            newPos = 0;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };

    Array.prototype.moveDown = function (value, by) {
        var index = this.indexOf(value),
            newPos = index + (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos >= this.length)
            newPos = this.length;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };



    var arr = ['banana', 'curyWurst', 'pc', 'remembaHaruMembaru'];

    alert('withiout changes= '+arr[0]+' ||| '+arr[1]+' ||| '+arr[2]+' ||| '+arr[3]);
    arr.moveDown(arr[2]);


    alert('third word moved down= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);
    arr.moveUp(arr[2]);
    alert('third word moved up= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview

Arthur Tsidkilov
  • 5,401
  • 2
  • 21
  • 18
4

Here's one way to do it in an immutable way. It handles negative numbers as well as an added bonus. This is reduces number of possible bugs at the cost of performance compared to editing the original array.

const numbers = [1, 2, 3];
const moveElement = (array, from, to) => {
  const copy = [...array];
  const valueToMove = copy.splice(from, 1)[0];
  copy.splice(to, 0, valueToMove);
  return copy;
};

console.log(moveElement(numbers, 0, 2))
// > [2, 3, 1]
console.log(moveElement(numbers, -1, -3))
// > [3, 1, 2] 
Caveman
  • 2,527
  • 1
  • 17
  • 18
3

Find and move an element from "n"th position to 0th position.

Eg: Find and move 'd' to 0th position:

let arr = [ 'a', 'b', 'c', 'd', 'e'];
arr = [...arr.filter(item => item === 'd'), ...arr.filter(item => item !== 'd')];
Harikrishnan
  • 9,688
  • 11
  • 84
  • 127
2

I ended up combining two of these to work a little better when moving both small and large distances. I get fairly consistent results, but this could probably be tweaked a little bit by someone smarter than me to work differently for different sizes, etc.

Using some of the other methods when moving objects small distances was significantly faster (x10) than using splice. This might change depending on the array lengths though, but it is true for large arrays.

function ArrayMove(array, from, to) {
    if ( Math.abs(from - to) > 60) {
        array.splice(to, 0, array.splice(from, 1)[0]);
    } else {
        // works better when we are not moving things very far
        var target = array[from];
        var inc = (to - from) / Math.abs(to - from);
        var current = from;
        for (; current != to; current += inc) {
            array[current] = array[current + inc];
        }
        array[to] = target;    
    }
}

https://web.archive.org/web/20181026015711/https://jsperf.com/arraymove-many-sizes

tagurit
  • 494
  • 5
  • 13
Andrew
  • 8,322
  • 2
  • 47
  • 70
2

It is stated in many places (adding custom functions into Array.prototype) playing with the Array prototype could be a bad idea, anyway I combined the best from various posts, I came with this, using modern Javascript:

    Object.defineProperty(Array.prototype, 'immutableMove', {
        enumerable: false,
        value: function (old_index, new_index) {
            var copy = Object.assign([], this)
            if (new_index >= copy.length) {
                var k = new_index - copy.length;
                while ((k--) + 1) { copy.push(undefined); }
            }
            copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
            return copy
        }
    });

    //how to use it
    myArray=[0, 1, 2, 3, 4];
    myArray=myArray.immutableMove(2, 4);
    console.log(myArray);
    //result: 0, 1, 3, 4, 2

Hope can be useful to anyone

BernieSF
  • 1,722
  • 1
  • 28
  • 42
2

This version isn't ideal for all purposes, and not everyone likes comma expressions, but here's a one-liner that's a pure expression, creating a fresh copy:

const move = (from, to, ...a) => (a.splice(to, 0, ...a.splice(from, 1)), a)

A slightly performance-improved version returns the input array if no move is needed, it's still OK for immutable use, as the array won't change, and it's still a pure expression:

const move = (from, to, ...a) => 
    from === to 
    ? a 
    : (a.splice(to, 0, ...a.splice(from, 1)), a)

The invocation of either is

const shuffled = move(fromIndex, toIndex, ...list)

i.e. it relies on spreading to generate a fresh copy. Using a fixed arity 3 move would jeopardize either the single expression property, or the non-destructive nature, or the performance benefit of splice. Again, it's more of an example that meets some criteria than a suggestion for production use.

Robert Monfera
  • 1,980
  • 1
  • 22
  • 16
2

const move = (from, to, ...a) =>from === to ? a : (a.splice(to, 0, ...a.splice(from, 1)), a);
const moved = move(0, 2, ...['a', 'b', 'c']);
console.log(moved)
Shijo Rs
  • 159
  • 1
  • 2
2

I thought this was a swap problem but it's not. Here's my one-liner solution:

const move = (arr, from, to) => arr.map((item, i) => i === to ? arr[from] : (i >= Math.min(from, to) && i <= Math.max(from, to) ? arr[i + Math.sign(to - from)] : item));

Here's a small test:

let test = ['a', 'b', 'c', 'd', 'e'];
console.log(move(test, 0, 2)); // [ 'b', 'c', 'a', 'd', 'e' ]
console.log(move(test, 1, 3)); // [ 'a', 'c', 'd', 'b', 'e' ]
console.log(move(test, 2, 4)); // [ 'a', 'b', 'd', 'e', 'c' ]
console.log(move(test, 2, 0)); // [ 'c', 'a', 'b', 'd', 'e' ]
console.log(move(test, 3, 1)); // [ 'a', 'd', 'b', 'c', 'e' ]
console.log(move(test, 4, 2)); // [ 'a', 'b', 'e', 'c', 'd' ]
console.log(move(test, 4, 0)); // [ 'e', 'a', 'b', 'c', 'd' ]
cagdas_ucar
  • 135
  • 1
  • 3
2

This is a really simple method using splice

Array.prototype.moveToStart = function(index) {
    this.splice(0, 0, this.splice(index, 1)[0]);
    return this;
  };
Nour Adel
  • 51
  • 3
2

I love immutable, functional one liners :) ...

const swapIndex = (array, from, to) => (
  from < to 
    ? [...array.slice(0, from), ...array.slice(from + 1, to + 1), array[from], ...array.slice(to + 1)] 
    : [...array.slice(0, to), array[from], ...array.slice(to, from), ...array.slice(from + 1)]
);
Dudley Craig
  • 157
  • 1
  • 5
1

Object oriented, expressive, debuggable, without mutation, tested.

class Sorter {
    sortItem(array, fromIndex, toIndex) {
        const reduceItems = () => {
            const startingItems = array.slice(0, fromIndex);
            const endingItems = array.slice(fromIndex + 1);
            return startingItems.concat(endingItems);
        }
        const addMovingItem = (movingItem, reducedItems) => {
            const startingNewItems = reducedItems.slice(0, toIndex);
            const endingNewItems = reducedItems.slice(toIndex);
            const newItems = startingNewItems.concat([movingItem]).concat(endingNewItems);
            return newItems;
        }
        const movingItem = array[fromIndex];
        const reducedItems = reduceItems();
        const newItems = addMovingItem(movingItem, reducedItems);
        return newItems;
    }
}

const sorter = new Sorter();
export default sorter;
import sorter from 'src/common/Sorter';

test('sortItem first item forward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['b', 'a', 'c', 'd'];
    expect(sorter.sortItem(startingArray, 0, 1)).toStrictEqual(expectedArray);
});
test('sortItem middle item forward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['a', 'c', 'b', 'd'];
    expect(sorter.sortItem(startingArray, 1, 2)).toStrictEqual(expectedArray);
});
test('sortItem middle item backward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['a', 'c', 'b', 'd'];
    expect(sorter.sortItem(startingArray, 2, 1)).toStrictEqual(expectedArray);
});
test('sortItem last item backward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['a', 'b', 'd', 'c'];
    expect(sorter.sortItem(startingArray, 3, 2)).toStrictEqual(expectedArray);
});
fabpico
  • 2,628
  • 4
  • 26
  • 43
0

Array.move.js

Summary

Moves elements within an array, returning an array containing the moved elements.

Syntax

array.move(index, howMany, toIndex);

Parameters

index: Index at which to move elements. If negative, index will start from the end.

howMany: Number of elements to move from index.

toIndex: Index of the array at which to place the moved elements. If negative, toIndex will start from the end.

Usage

array = ["a", "b", "c", "d", "e", "f", "g"];

array.move(3, 2, 1); // returns ["d","e"]

array; // returns ["a", "d", "e", "b", "c", "f", "g"]

Polyfill

Array.prototype.move || Object.defineProperty(Array.prototype, "move", {
    value: function (index, howMany, toIndex) {
        var
        array = this,
        index = parseInt(index) || 0,
        index = index < 0 ? array.length + index : index,
        toIndex = parseInt(toIndex) || 0,
        toIndex = toIndex < 0 ? array.length + toIndex : toIndex,
        toIndex = toIndex <= index ? toIndex : toIndex <= index + howMany ? index : toIndex - howMany,
        moved;

        array.splice.apply(array, [toIndex, 0].concat(moved = array.splice(index, howMany)));

        return moved;
    }
});
  • 2
    While the `.move` looks like it should work (I haven't tested it), you should note that it isn't part of any standard. It is also good to warn folks that polyfill/monkeypatched functions can break some code that assumes everything enumerable is theirs. – Jeremy J Starcher Sep 18 '12 at 19:06
  • 1
    a=["a", "b", "c"];a.move(0,1,1); // a = ["a", "b", "c"], should be ["b", "a", "c"] – Leonard Pauli Jul 15 '13 at 17:11
  • 2
    This feature is obsolete and may not supported any more. Be careful See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/move – Mostafa Barmshory Mar 18 '18 at 12:45
0

I used the nice answer of @Reid, but struggled with moving an element from the end of an array one step further - to the beginning (like in a loop). E.g. ['a', 'b', 'c'] should become ['c', 'a', 'b'] by calling .move(2,3)

I achieved this by changing the case for new_index >= this.length.

Array.prototype.move = function (old_index, new_index) {
        console.log(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) {
            new_index = new_index % this.length;
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this; // for testing purposes
    };
Community
  • 1
  • 1
0

As an addition to Reid's excellent answer (and because I cannot comment); You can use modulo to make both negative indices and too large indices "roll over":

function array_move(arr, old_index, new_index) {
  new_index =((new_index % arr.length) + arr.length) % arr.length;
  arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
  return arr; // for testing
}

// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1)); 
Didi
  • 49
  • 2
  • Yes - since negative indices are supported, it seems sensible to wrap too-large indices rather than inserting undefined values, in my opinion. – pythonjsgeo Oct 18 '18 at 22:22
0
let ar = ['a', 'b', 'c', 'd'];

function change( old_array, old_index , new_index ){

  return old_array.map(( item , index, array )=>{
    if( index === old_index ) return array[ new_index ];
    else if( index === new_index ) return array[ old_index ];
    else return item;
  });

}

let result = change( ar, 0, 1 );

console.log( result );

result:

["b", "a", "c", "d"]
Naycho334
  • 167
  • 2
  • 11
0

    let oldi, newi, arr;
    
    if(newi !== oldi) {
      let el = this.arr.splice(oldi, 1);
      if(newi > oldi && newi === (this.arr.length + 2)) {
        this.arr.push("");
      }
      this.arr.splice(newi, 0, el);
      if(newi > oldi && newi === (this.arr.length + 2)) {
        this.arr.pop();
      }
    }
behnam
  • 61
  • 1
  • 4
0

var ELEMS = ['a', 'b', 'c', 'd', 'e'];
/*
    Source item will remove and it will be placed just after destination
*/
function moveItemTo(sourceItem, destItem, elements) {
    var sourceIndex = elements.indexOf(sourceItem);
    var destIndex = elements.indexOf(destItem);
    if (sourceIndex >= -1 && destIndex > -1) {
        elements.splice(destIndex, 0, elements.splice(sourceIndex, 1)[0]);
    }
    return elements;
}
console.log('Init: ', ELEMS);
var result = moveItemTo('a', 'c', ELEMS);
console.log('BeforeAfter: ', result);
0

Immutable version without array copy:

const moveInArray = (arr, fromIndex, toIndex) => {
  if (toIndex === fromIndex || toIndex >= arr.length) return arr;

  const toMove = arr[fromIndex];
  const movedForward = fromIndex < toIndex;

  return arr.reduce((res, next, index) => {
    if (index === fromIndex) return res;
    if (index === toIndex) return res.concat(
      movedForward ? [next, toMove] : [toMove, next]
    );

    return res.concat(next);
  }, []);
};
VoloshinS
  • 26
  • 3
0

I think the best way is define a new property for Arrays

Object.defineProperty(Array.prototype, 'move', {
    value: 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) {
            let k = new_index - this.length;
            while ((k--) + 1) {
                this.push(undefined);
            }
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this;
    }
});

console.log([10, 20, 30, 40, 50].move(0, 1));  // [20, 10, 30, 40, 50]
console.log([10, 20, 30, 40, 50].move(0, 2));  // [20, 30, 10, 40, 50]
iProDev
  • 547
  • 6
  • 5
0

This method will preserve the original array, and check for bounding errors.

const move = (from, to, arr) => {
    to = Math.max(to,0)
    from > to 
        ? [].concat(
            arr.slice(0,to), 
            arr[from], 
            arr.filter((x,i) => i != from).slice(to)) 
        : to > from
            ? [].concat(
                arr.slice(0, from), 
                arr.slice(from + 1, to + 1), 
                arr[from], 
                arr.slice(to + 1))
            : arr}
nikk wong
  • 8,059
  • 6
  • 51
  • 68
0

In your example, because is an array of string we can use a ranking object to reorder the string array:

let rank =  { 'a': 0, 'b': 1, 'c': 2, 'd': 0.5, 'e': 4 };
arr.sort( (i, j) => rank[i] - rank[j] );

We can use this approach to write a move function that works on a string array:

function stringArrayMove(arr, from, to)
{
  let rank = arr.reduce( (p, c, i) => ( p[c] = i, p ), ({ }) );
  // rank = { 'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4 }
  rank[arr[from]] = to - 0.5;
  // rank = { 'a': 0, 'b': 1, 'c': 2, 'd': 1.5, 'e': 4 }
  arr.sort( (i, j) => rank[i] - rank[j] );
  // arr = [ 'a', 'd', 'b', 'c', 'e' ];
}

let arr = [ 'a', 'b', 'c', 'd', 'e' ];
stringArrayMove(arr, 3, 1);
console.log( JSON.stringify(arr) );

If, however, the thing we wanted to sort is an array of object, we can introduce the ranking as a new property of each object, i.e.

let arr = [ { value: 'a', rank: 0 },
            { value: 'b', rank: 1 },
            { value: 'c', rank: 2 },
            { value: 'd', rank: 0.5 },
            { value: 'e', rank: 4 } ];
arr.sort( (i, j) => i['rank'] - j['rank'] );

We can use Symbol to hide the visibility of this property, i.e. it will not be shown in JSON.stringify. We can generalize this in an objectArrayMove function:

function objectArrayMove(arr, from, to) {
  let rank = Symbol("rank");
  arr.forEach( (item, i) => item[rank] = i );
  arr[from][rank] = to - 0.5;
  arr.sort( (i, j) => i[rank] - j[rank]);
}
let arr = [ { value: 'a' }, { value: 'b' }, { value: 'c' }, { value: 'd' }, { value: 'e' } ];
console.log( 'array before move: ', JSON.stringify( arr ) );
// array before move:  [{"value":"a"},{"value":"b"},{"value":"c"},{"value":"d"},{"value":"e"}]
objectArrayMove(arr, 3, 1);
console.log( 'array after move: ', JSON.stringify( arr ) );
// array after move:  [{"value":"a"},{"value":"d"},{"value":"b"},{"value":"c"},{"value":"e"}]
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
0

If the object is nested:

  let array = ['a', 'b', 'c', 'd', 'e'];
  let existingElement = JSON.parse(JSON.stringify(array[3]));
  array.splice(1, 0, existingElement);
  array.splice(4, 1);
  console.log(array)
leoncc
  • 233
  • 3
  • 6
0

I resolved my issue using immutability-helper library.

import update from 'immutability-helper';

const move = (arr: any[], from: number, to: number) => update(arr, {
  $splice: [
    [from, 1],
    [to, 0, arr[from] as string],
  ],
});

const testArray = ['a', 'b', 'c', 'd', 'e'];
console.log(move(testArray, 1, 3)); // [ 'c', 'b', 'c', 'd', 'e' ]
console.log(move(testArray, 4, 0)); // [ 'e', 'b', 'c', 'd', 'a' ]
Maqsood Ahmed
  • 1,853
  • 1
  • 10
  • 18
0

As with everything, the full use is what matters.

There are perfectly fine answers here for a single move, and for both small and large data sets. If you're doing thousands of moves though, I'd suggest looking at states and less-frequent intensive operations. Something like:

  • Change your data set, keep an order "status" against each item.
  • Apply thousands of updates.
  • Perform a single sort on that order attribute.
 ["a", "b", "c"]

would change to

[
   {val: 'a', order: 0},
   {val: 'b', order: 1},
   {val: 'c', order: 2},

]

Then, apply thousands of updates.

Finally, you sort by the "order" variable. And perhaps renumber things too.

I haven't tested the performance of this, but can imagine at a certain level of usage it'd be better than trying to rebuild arrays every 1000s of times.

Sandeep
  • 65
  • 5
0

We can move array element from one position to another position in many ways. Here I try to solve this in 3 ways in immutably.

Move array element using splice where time complexity is Quadratic Time - O(n^2)

function arrayMove(arr, oldIndex, newIndex) {
  const copiedArr = [...arr];
  const length = copiedArr.length;
  
  if (oldIndex !== newIndex && length > oldIndex && length > newIndex) {
    copiedArr.splice(newIndex, 0, copiedArr.splice(oldIndex, 1)[0]);
  }
  
  return copiedArr;
}

arrayMove([1,2,3,4], 0, 3) // [2,3,4,1]

Move array element using flatMap where time complexity is Linear Time - O(n)

function arrayMove(arr, oldIndex, newIndex) {
    const length = arr.length;
    const itemToMove = arr[oldIndex]

    if (oldIndex === newIndex || oldIndex > length || newIndex > length) {
        return arr;
    }

    return arr.flatMap((item, index) => {
        if (index === oldIndex) return [];
        if (index === newIndex) return oldIndex < newIndex ? [item, itemToMove] : [itemToMove, item];
        return item;
    })
}

arrayMove([1,2,3,4], 0, 3) // [2,3,4,1]

Move array element using reduce where time complexity is Linear Time - O(n)

function arrayMove(arr, oldIndex, newIndex) {
    const length = arr.length;
    const itemToMove = arr[oldIndex]

    if (oldIndex === newIndex || oldIndex > length || newIndex > length) {
        return arr;
    }

    return arr.reduce((acc, item, index) => {
        if (index === oldIndex) return acc;
        if (index === newIndex) return oldIndex < newIndex ? [...acc, item, itemToMove] : [...acc, itemToMove, item];
        return [...acc, item];
    }, [])
}

arrayMove([1,2,3,4], 0, 3) // [2,3,4,1]

You can also checkout this gist: Move an array element from one array position to another

Foyez
  • 334
  • 3
  • 9
0

Just simple mutable solution without any splice or other array functions with complexity of O(n) without using any memory allocations.

If the desired index is out of array boundaries, it will move element to end/start of the array.

function moveArray(arr, from, to) {
    if (from >= arr.length || from < 0) throw Error('Out of boundaries'); // cover edge cases for moving element
    const increment = from > to ? -1 : 1; // where to move others (up/down)
    to = increment > 0 ? Math.min(to, arr.length - 1) : Math.max(to, 0); // cover edge cases for placement (start/end)
    if (from === to) return;
    const target = arr[from];
    while (from !== to) arr[from] = arr[(from += increment)]; // move elements in between
    arr[to] = target; // place target at desired index
}

// test/example
const arr = [2,3,4,5,6,7,8];
moveArray(arr, 2, 4);

console.log(arr); // [ 2, 3, 5, 6, 4, 7, 8 ]

moveArray(arr, 3, 11);
console.log(arr); // [ 2, 3, 5, 4, 7, 8, 6 ]

moveArray(arr, 6, -1);
console.log(arr); // [ 6, 2, 3, 5, 4, 7, 8 ]
Filip Kováč
  • 499
  • 8
  • 15
0

@abr's answer is near perfect, but it misses one edge case where if you try and access a key that does not exist in the array, it actually returns an array 1 entry larger than the original. This fixes that bug.

let move = (arr, from, to) => {
        const smallerIndex = Math.min(from, to);
        const largerIndex = Math.max(from, to);
        
        /**
            Bail early if array does not have the target key, to avoid 
            edge case where trying to move an undefined key
            results in the array growing 1 entry in size with an undefined value
        */
        
        if(!arr.hasOwnProperty(from)) return arr
    
        return [
            
            ...arr.slice(0, smallerIndex),
            
            ...(
                from < to
                    ? arr.slice(smallerIndex + 1, largerIndex + 1)
                    : []
            ),
            
            arr[from],
    
            ...(
                from > to
                    ? arr.slice(smallerIndex, largerIndex)
                    : []
            ),
    
            ...arr.slice(largerIndex + 1),
    
        ];
    }
    
    
    let arr = [
        0, 1, 2, 3, 4, 5
    ];
    console.log(move(arr, -30, -45));
    console.log(move(arr, 0, -45));
    console.log(move(arr, 0, 1));
    console.log(move(arr, 0, 0));
    console.log(move(arr, 5, 5));
Hybrid web dev
  • 328
  • 4
  • 15
0

With Angular U could use the angular/cdk/drag-drop API. Either when actually using drag&drop or as standalone:

npm install @angular/cdk

app.module.ts:

import {DragDropModule} from '@angular/cdk/drag-drop';

In componentXY.ts:

import { CdkDragDrop, CdkDragEnd, CdkDragStart, moveItemInArray } from '@angular/cdk/drag-drop';

  onDrop(event: CdkDragDrop<any>) {
    // handle drop event
    console.log("onDrop", event)
    moveItemInArray(this.codes, event.previousIndex, event.currentIndex);
  }
CAoT
  • 183
  • 2
  • 10
0

You can use this to convert from Object to array, move the index than reconvert in Object

 function x(obje, oldIndex, newIndex) {
        var newArr = Object.entries(obje);
        var finalObj = new Object();
        newArr.splice(newIndex,0,newArr.splice(oldIndex,1)[0]);
        //-- Convert again in object
        finalObj = newArr.reduce( (obj, item) => Object.assign(obj, { [item[0]]: item[1] }), {});
        return finalObj;
    }
var obj = {
  "x.pdf": {
    "sizeFmt": " <samp>(107.64 KB)</samp>"
  },
  "y.pdf": {
    "sizeFmt": " <samp>(364.34 KB)</samp>"
  },
  "z.pdf": {
    "sizeFmt": " <samp>(111.81 KB)</samp>"
  }
};
console.log(obj);
obj = x(obj, 0, 1);
console.log(obj);
BoBiTza
  • 98
  • 13
0

Using modern JavaScript (as of 2023) without mutating the array:

function move(array, targetIndex, beforeIndex) {
  if (targetIndex < beforeIndex) {
    // Moves forward
    return [
      ...array.slice(0, targetIndex),
      ...array.slice(targetIndex + 1, beforeIndex),
      array.at(targetIndex),
      ...array.slice(beforeIndex),
    ];
  }

  if (targetIndex > beforeIndex) {
    // Moves back
    return [
      ...array.slice(0, beforeIndex),
      array.at(targetIndex),
      ...array.slice(beforeIndex, targetIndex),
      ...array.slice(targetIndex + 1),
    ];
  }
  
  // Stayes in place
  return [...array];
}

const letters = [ "a", "b", "c", "d", "e"];

// Move te d back, before the b
console.log(move(letters, letters.indexOf("d"), letters.indexOf("b")));

// Move the b forward, before the d
console.log(move(letters, letters.indexOf("b"), letters.indexOf("d")));

// Have the c stay in place
console.log(move(letters, letters.indexOf("c"), 3));
Rúnar Berg
  • 4,229
  • 1
  • 22
  • 38
0

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

const fromIndex = array.indexOf('e');

const toIndex = 1;

const element = array.splice(fromIndex, 1)[0];

array.splice(toIndex, 0, element);

console.log(array).

// output ['a','e', 'b', 'c', 'd']

sherkhan
  • 811
  • 8
  • 8