我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:
var array = [ 'a', 'b', 'c', 'd', 'e'];
我怎么能写一个函数来移动元素'd'到'b'的左边?
还是c右边的a ?
移动元素之后,应该更新其余元素的索引。结果数组将是:
array = ['a', 'd', 'b', 'c', 'e']
这看起来应该很简单,但我无法理解它。
我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:
var array = [ 'a', 'b', 'c', 'd', 'e'];
我怎么能写一个函数来移动元素'd'到'b'的左边?
还是c右边的a ?
移动元素之后,应该更新其余元素的索引。结果数组将是:
array = ['a', 'd', 'b', 'c', 'e']
这看起来应该很简单,但我无法理解它。
当前回答
这里有一种方法可以用不变的方式来做。它处理负数以及一个额外的奖励。与编辑原始数组相比,这以性能为代价减少了可能的错误数量。
const numbers = [1, 2, 3];
const moveElement = (array, from, to) => {
const copy = [...array];
const valueToMove = copy.splice(from, 1)[0];
copy.splice(to, 0, valueToMove);
return copy;
};
console.log(moveElement(numbers, 0, 2))
// > [2, 3, 1]
console.log(moveElement(numbers, -1, -3))
// > [3, 1, 2]
其他回答
我最终将这两种方法结合起来,以便在移动小距离和大距离时更好地工作。我得到了相当一致的结果,但这可能会被比我更聪明的人稍微调整一下,以不同的大小工作,等等。
在小距离移动对象时,使用其他一些方法明显比使用拼接快(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
let ar = ['a', 'b', 'c', 'd'];
function change( old_array, old_index , new_index ){
return old_array.map(( item , index, array )=>{
if( index === old_index ) return array[ new_index ];
else if( index === new_index ) return array[ old_index ];
else return item;
});
}
let result = change( ar, 0, 1 );
console.log( result );
结果:
["b", "a", "c", "d"]
下面是我在JSPerf....上找到的一行代码
Array.prototype.move = function(from, to) {
this.splice(to, 0, this.splice(from, 1)[0]);
};
这是很棒的阅读,但如果你想要性能(在小数据集)尝试……
Array.prototype.move2 = function(pos1, pos2) {
// local variables
var i, tmp;
// cast input parameters to integers
pos1 = parseInt(pos1, 10);
pos2 = parseInt(pos2, 10);
// if positions are different and inside array
if (pos1 !== pos2 && 0 <= pos1 && pos1 <= this.length && 0 <= pos2 && pos2 <= this.length) {
// save element from position 1
tmp = this[pos1];
// move element down and shift other elements up
if (pos1 < pos2) {
for (i = pos1; i < pos2; i++) {
this[i] = this[i + 1];
}
}
// move element up and shift other elements down
else {
for (i = pos1; i > pos2; i--) {
this[i] = this[i - 1];
}
}
// put element from position 1 to destination
this[pos2] = tmp;
}
}
这不是我的功劳,这都应该归功于理查德·斯卡洛特。在这个性能测试中,它在较小的数据集上击败了基于拼接的方法。然而,正如Darwayne指出的那样,在较大的数据集上,它要慢得多。
如果对象是嵌套的:
let array = ['a', 'b', 'c', 'd', 'e'];
let existingElement = JSON.parse(JSON.stringify(array[3]));
array.splice(1, 0, existingElement);
array.splice(4, 1);
console.log(array)
我使用不可变性助手库解决了我的问题。
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' ]