Mark Brown
Mark Brown

Reputation: 12524

Move an array element from one array position to another

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.

Upvotes: 793

Views: 840058

Answers (30)

Harikrishnan
Harikrishnan

Reputation: 9979

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')];
console.log(arr);

Upvotes: 4

Steak Overflow
Steak Overflow

Reputation: 7618

I like this method as it's concise and it just 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.

The following snippet prints a few tests in console to show all combinations of fromIndex and toIndex (0..n, 0..n) work.

Run Snippet in jsFiddle

Upvotes: 563

Gass
Gass

Reputation: 9344

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

Upvotes: 8

Mohd Sher Khan
Mohd Sher Khan

Reputation: 1087

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

Upvotes: -1

Rúnar Berg
Rúnar Berg

Reputation: 4832

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

Upvotes: 0

BoBiTza
BoBiTza

Reputation: 98

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

Upvotes: 0

CAoT
CAoT

Reputation: 192

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

Upvotes: 0

Hybrid web dev
Hybrid web dev

Reputation: 340

@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));

Upvotes: 1

Filip Kov&#225;č
Filip Kov&#225;č

Reputation: 579

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 ]

Upvotes: 0

kinoli
kinoli

Reputation: 149

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

Upvotes: 8

Foyez
Foyez

Reputation: 464

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

Upvotes: 2

FirstVertex
FirstVertex

Reputation: 3785

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

Upvotes: 5

Sandeep
Sandeep

Reputation: 65

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.

Upvotes: 0

fabpico
fabpico

Reputation: 2927

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

Upvotes: 1

Maqsood Ahmed
Maqsood Ahmed

Reputation: 2257

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

Upvotes: 0

Andrew
Andrew

Reputation: 8674

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

Upvotes: 2

Andrea
Andrea

Reputation: 107

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

Upvotes: 10

digiguru
digiguru

Reputation: 12829

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.

Upvotes: 335

Dudley Craig
Dudley Craig

Reputation: 157

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

Upvotes: 2

Caveman
Caveman

Reputation: 2955

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] 

Upvotes: 4

Elie Teyssedou
Elie Teyssedou

Reputation: 779

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.

Upvotes: 28

leoncc
leoncc

Reputation: 233

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)

Upvotes: 0

Stephen Quan
Stephen Quan

Reputation: 25956

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

Upvotes: 0

Nour Adel
Nour Adel

Reputation: 61

This is a really simple method using splice

Array.prototype.moveToStart = function(index) {
    this.splice(0, 0, this.splice(index, 1)[0]);
    return this;
  };

Upvotes: 2

nikk wong
nikk wong

Reputation: 8670

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}

Upvotes: 0

abr
abr

Reputation: 169

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

Upvotes: 6

iProDev
iProDev

Reputation: 603

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]

Upvotes: 0

VoloshinS
VoloshinS

Reputation: 26

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);
  }, []);
};

Upvotes: 0

cagdas_ucar
cagdas_ucar

Reputation: 205

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

Upvotes: 2

Mohd Abdul Baquee
Mohd Abdul Baquee

Reputation: 449

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

Upvotes: 0

Related Questions