Change elements positions in an array and shift elements in between

Khalil Khalaf picture Khalil Khalaf · Jul 5, 2017 · Viewed 15.9k times · Source

I would like to pick an element in an array, move it to another index, and then "shift/rotate" the "in-between" elements by 1.

Imagine a drag and drop functionality, if the index from is less than index to, then I would like to shift to be to the left, and else shift to be to the right.

Input:

let data = [ 0, 1, 2, 3, 4, 5, 6 ]

Task1: insertAndShift(data, 0, 3): Take element at index 0, shift indexes 1, 2, 3 to the left, and then insert index 0 at 3

Expected Output:

[ 1, 2, 3, 0, 4, 5, 6 ]

Task2: insertAndShift(data, 3, 0) Take element at index 3, shift indexes 0, 1, 2 to the right and then insert index 3 at 0

Expected Output:

[ 0, 1, 2, 3, 4, 5, 6 ]

I tried this:

Following Rotating an array in place, ugly and not working code (temp always undefined + result is not complete + possible work only for RIGHT):

insertAndShift(data, from, to)
{
    if(from < to)
    {
        // rotate in between - LEFT

    }
    else
    {    
        // swap elements
        let temp = data[from];
        data[from] = data[to];
        data[to] = temp;

        // rotate in between - RIGHT
        let newData = this.rotate(data.slice(to, from - 1), 1)

        let result = [];
        result.push(data.slice(0,1));
        newData.map((element) => result.push(element))
        for(let i = from+1; i < data.length; i++)
        {
            result.push(data[i]);
        }

        this.setState({data: result})
    }
}

rotate(arr, k) {
    var l = arr.length;
    arr = this.reverseArr(arr, 0, l - 1);
    arr = this.reverseArr(arr, 0, k - 1);
    arr = this.reverseArr(arr, k, l - 1);
    return arr;
}

reverseArr(arr, left, right) {
    while (left < right) {
        var temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
        left++;
        right--;
    }
    return arr;
}

Also following Javascript (dynamic) insert into array, then shift all elements underneath +1, which returns only 1 item:

else
{
    let result = data.splice(to, 1, data[from]);
    this.setState({allTasksArray: result})
}

How can I achieve this for both Left and Right?

Answer

ibrahim mahrir picture ibrahim mahrir · Jul 5, 2017

You can use Array.prototype.splice to cut out the element you want and insert at the desired index (the shifting will happen automatically):

function insertAndShift(arr, from, to) {
    let cutOut = arr.splice(from, 1) [0]; // cut the element at index 'from'
    arr.splice(to, 0, cutOut);            // insert it at index 'to'
}



let data = [ 0, 1, 2, 3, 4, 5, 6 ];

insertAndShift(data, 0, 3);
console.log("[" + data + "]");

insertAndShift(data, 3, 0);
console.log("[" + data + "]");