将数组元素从一个数组位置移动到另一个数组位置
我很难弄清楚如何移动数组的元素。例如,给定以下内容:
var array = [ 'a', 'b', 'c', 'd', 'e'];
我如何编写一个函数来将元素
'd'
移动到
'b'
的左侧?
或者将
'a'
移动到
'c'
的右侧?
移动元素后,其余元素的索引应更新。生成的数组将是:
array = ['a', 'd', 'b', 'c', 'e']
这似乎应该很简单,但我无法理解它。
如果您想要 npm 上的版本, array-move 与此答案最接近,尽管它们的实现不同。有关更多详细信息,请参阅其使用部分。可以在 npm 上的 array.prototype.move 找到此答案的先前版本(修改了 Array.prototype.move)。
我使用此函数取得了相当不错的成功:
function array_move(arr, old_index, new_index) {
if (new_index >= arr.length) {
var k = new_index - arr.length + 1;
while (k--) {
arr.push(undefined);
}
}
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr; // for testing
};
// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1));
请注意,最后一个
return
仅用于测试目的:
splice
在数组上执行操作,因此无需返回。通过扩展,此
move
是一个就地操作。如果您想避免这种情况并返回副本,请使用
slice
。
逐步执行代码:
-
如果
new_index
大于数组的长度,我们希望(我推测)用新的undefined
正确填充数组。这个小代码片段通过将undefined
推送到数组上直到我们获得适当的长度来处理这个问题。 -
然后,在
arr.splice(old_index, 1)[0]
中,我们拼接出旧元素。splice
返回拼接出的元素,但它在数组中。在我们上面的例子中,这是[1]
。因此,我们取该数组的第一个索引,以获得原始的1
。 -
然后我们使用
splice
将此元素插入 new_index 的位置。由于我们在new_index > arr.length
的情况下填充了上面的数组,因此它可能会出现在正确的位置,除非他们做了一些奇怪的事情,例如传入一个负数。
一个更精致的版本来解释负索引:
function array_move(arr, old_index, new_index) {
while (old_index < 0) {
old_index += arr.length;
}
while (new_index < 0) {
new_index += arr.length;
}
if (new_index >= arr.length) {
var k = new_index - arr.length + 1;
while (k--) {
arr.push(undefined);
}
}
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
return arr; // for testing purposes
};
// returns [1, 3, 2]
console.log(array_move([1, 2, 3], -1, -2));
它应该正确解释
array_move([1, 2, 3], -1, -2)
之类的事情(将最后一个元素移动到倒数第二个位置)。结果应该是
[1, 3, 2]
。
无论哪种方式,在您的原始问题中,您都会在
c
之后对
a
执行
array_move(arr, 0, 2)
。对于
b
之前的
d
,您将执行
array_move(arr, 3, 1)
。
我喜欢这种方法,因为它很简洁,而且很有效。
579236644
注意:始终记住检查您的数组界。
以下snippet在控制台中打印一些测试,以显示
fromIndex
和
toIndex
(0..N,0..N)
工作的所有组合。
p>
这是我在 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;
}
}
我不能承担任何功劳,这应该全部归功于 Richard Scarrott 。在这项 性能测试 中,它击败了针对较小数据集的基于拼接的方法。然而,正如 Darwayne 指出的那样 ,它在较大的数据集上的速度明显较慢。