我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:

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

我怎么能写一个函数来移动元素'd'到'b'的左边?

还是c右边的a ?

移动元素之后,应该更新其余元素的索引。结果数组将是:

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

这看起来应该很简单,但我无法理解它。


当前回答

我以为这是个交换问题,但其实不是。下面是我的一句话解决方案:

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

下面是一个小测试:

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

其他回答

我以为这是个交换问题,但其实不是。下面是我的一句话解决方案:

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

下面是一个小测试:

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

Const move = (from, to,…a) =>from === to ?A: (A .splice(to, 0,…Splice (from, 1)), a); Const moved = move(0, 2,…['a', 'b', 'c']); console.log(移动)

我最终将这两种方法结合起来,以便在移动小距离和大距离时更好地工作。我得到了相当一致的结果,但这可能会被比我更聪明的人稍微调整一下,以不同的大小工作,等等。

在小距离移动对象时,使用其他一些方法明显比使用拼接快(x10)。这可能会根据数组的长度而改变,但对于大型数组是正确的。

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

Array的splice方法可能有帮助:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

请记住,它可能相对昂贵,因为它必须主动重新索引数组。

打印稿版本

摘自@Merc的回答。我最喜欢这个,因为它没有创建新的数组,而是在适当的地方修改数组。我所做的只是更新到ES6并添加类型。

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