Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change elements positions in an array and shift elements in between

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?

like image 944
Khalil Khalaf Avatar asked Jul 05 '17 17:07

Khalil Khalaf


People also ask

What is shift and Unshift?

What are Shift() and Unshift() methods in JavaScript. The shift() method is used to remove an element/item from the starting point of an array. The unshift() method is used to add an element/item to the starting point of an array.

Is shift () destructive?

Shift is destructive. It removes the first element of an array, and returns the removed element.

Can you change the elements in an array?

Replace an Element in an Array using Array. Use the indexOf() method to get the index of the element you want to replace. Call the Array. splice() method to replace the element at the specific index. The array element will get replaced in place.


2 Answers

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 + "]");
like image 81
ibrahim mahrir Avatar answered Sep 18 '22 15:09

ibrahim mahrir


The answer above works great but it's a little handwavy... if you are interested in a solution that spells out what it's doing I wrote this:

const insertAndShift = (arr: number[], to: number, from: number) => {
  let newArray: number[] = [];
  const fromItem = arr[from];
  if (from > to) {
    const startToTo = (to > 0) ? arr.slice(0, to) : [];
    const toToFrom = arr.slice(to, from);
    const fromToEnd = arr.slice(from + 1, arr.length);
    newArray = newArray.concat(startToTo, [fromItem], toToFrom, fromToEnd);
  }
  if (to > from) {
    const startToFrom = (from > 0) ? arr.slice(0, from) : [];
    const fromToTo = arr.slice(from + 1, to + 1);
    const toToEnd = arr.slice(to + 1, arr.length);
    newArray = newArray.concat(startToFrom, fromToTo, fromItem, toToEnd);
  }
  return newArray;
};

const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

console.log(insertAndShift(array, 9, 0));
console.log(insertAndShift(array, 5, 1));
like image 25
Devin Clark Avatar answered Sep 21 '22 15:09

Devin Clark