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

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

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

还是c右边的a ?

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

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

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


当前回答

这个版本并不适合所有目的,也不是每个人都喜欢逗号表达式,但这里有一个纯表达式,创建了一个新的副本:

const move = (from, to, ...a) => (a.splice(to, 0, ...a.splice(from, 1)), a)

性能略有改进的版本在不需要移动的情况下返回输入数组,它仍然可以用于不可变的用途,因为数组不会改变,并且它仍然是一个纯表达式:

const move = (from, to, ...a) => 
    from === to 
    ? a 
    : (a.splice(to, 0, ...a.splice(from, 1)), a)

两者的调用都是

const shuffled = move(fromIndex, toIndex, ...list)

也就是说,它依靠传播来产生一个新的副本。使用固定值3的移动会危及单个表达式的属性,或非破坏性的性质,或拼接的性能优势。同样,它更像是一个满足某些标准的示例,而不是供生产使用的建议。

其他回答

另一个纯JS变体使用ES6数组展开运算符,没有突变

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

不复制数组的不可变版本:

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

我使用不可变性助手库解决了我的问题。

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

打印稿版本

摘自@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;
}

找到并移动一个元素从第n个位置到第0个位置。

找到并移动“d”到第0个位置:

let arr = [ 'a', 'b', 'c', 'd', 'e'];
arr = [...arr.filter(item => item === 'd'), ...arr.filter(item => item !== 'd')];