在数组中改变元素的位置并移动元素

10

我想在数组中选择一个元素,将其移动到另一个索引,然后将“中间”元素“转移/旋转”1次。

想象一下拖放功能,如果索引from小于索引to,则希望向左移动,否则向右移动。

输入:

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

任务1: insertAndShift(data,0,3):取出索引0处的元素,将索引1、2、3向左移动一个位置,然后将索引0插入到索引3处

期望输出:

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

任务2: insertAndShift(data,3,0):取出索引3处的元素,将索引0、1、2向右移动一个位置,然后将索引3插入到索引0处

期望输出:

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

我尝试了这个:

根据旋转数组代码,丑陋且无法工作(temp始终未定义+结果不完整+可能仅适用于右侧):

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

还有一个类似于JavaScript中动态插入数组,然后将下面所有元素都向下移动+1的问题,该问题仅返回了一个项目:

else
{
    let result = data.splice(to, 1, data[from]);
    this.setState({allTasksArray: result})
}
如何同时实现左右两侧?

你的预期输出为2号示例应该是3,0,1,2,4,5,6..? - EricG
@EricG 如果我在 Task1 的结果上应用函数 而不是初始的 data 上(这就是我在 OP 中的意思),那么就不会出现这种情况。 - Khalil Khalaf
3个回答

31

您可以使用 Array.prototype.splice 方法来剪切您想要的元素,并将其插入到所需的索引位置(移位将自动发生):

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


2

上面的答案很好,但有点简略...如果您想了解一个详细解释的解决方案,我写了下面这个:

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


增加了一些合理性检查,并针对TypeScript进行了微调,但基本原理相同!https://codepen.io/spjpgrd/pen/zYxjoEO?editors=0011 - spjpgrd

1

看一下这个方法:Array.prototype.copyWithin()

有一种更高效的原地方法来实现:

function insertAndShift(data, src, dest) {
    if (src === dest)
        return;

    let tmp = data[src];
    if (src < dest) {
        data.copyWithin(src, src + 1, dest + 1);
    } else /* if (src > dest) */ {
        data.copyWithin(dest + 1, dest, src);
    }
    data[dest] = tmp;
}

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

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

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

以下是一个示例:

下面是一个示例:

Case 1 (src < dest):
[..Sabcd..]
    ////       // data.copyWithin(src, src+1, dest+1);
[..abcdd..]
[..abcdS..]    // data[dest] = tmp;

Case 2 (src > dest):
[..abcdS..]
    \\\\       // data.copyWithin(dest+1, dest, src);
[..aabcd..]
[..Sabcd..]    // data[dest] = tmp;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接