我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:
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']
这看起来应该很简单,但我无法理解它。
当前回答
您可以实现一些基本的演算,并创建一个通用函数来将数组元素从一个位置移动到另一个位置。
对于JavaScript,它看起来是这样的:
function magicFunction (targetArray, indexFrom, indexTo) {
targetElement = targetArray[indexFrom];
magicIncrement = (indexTo - indexFrom) / Math.abs (indexTo - indexFrom);
for (Element = indexFrom; Element != indexTo; Element += magicIncrement){
targetArray[Element] = targetArray[Element + magicIncrement];
}
targetArray[indexTo] = targetElement;
}
查看“移动数组元素”在“忧郁”的详细解释。
https://web.archive.org/web/20121105042534/http://www.gloommatter.com:80/DDesign/programming/moving-any-array-elements-universal-function.html
其他回答
我最终将这两种方法结合起来,以便在移动小距离和大距离时更好地工作。我得到了相当一致的结果,但这可能会被比我更聪明的人稍微调整一下,以不同的大小工作,等等。
在小距离移动对象时,使用其他一些方法明显比使用拼接快(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
请记住,它可能相对昂贵,因为它必须主动重新索引数组。
另一个纯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 move = (from, to, arr) => {
to = Math.max(to,0)
from > to
? [].concat(
arr.slice(0,to),
arr[from],
arr.filter((x,i) => i != from).slice(to))
: to > from
? [].concat(
arr.slice(0, from),
arr.slice(from + 1, to + 1),
arr[from],
arr.slice(to + 1))
: arr}
这是基于@Reid的解决方案。除了:
我不会改变数组原型。 向右移动一个项目并不会创建未定义的项目,它只是将项目移动到最右边的位置。
功能:
function move(array, oldIndex, newIndex) {
if (newIndex >= array.length) {
newIndex = array.length - 1;
}
array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
return array;
}
单元测试:
describe('ArrayHelper', function () {
it('Move right', function () {
let array = [1, 2, 3];
arrayHelper.move(array, 0, 1);
assert.equal(array[0], 2);
assert.equal(array[1], 1);
assert.equal(array[2], 3);
})
it('Move left', function () {
let array = [1, 2, 3];
arrayHelper.move(array, 1, 0);
assert.equal(array[0], 2);
assert.equal(array[1], 1);
assert.equal(array[2], 3);
});
it('Move out of bounds to the left', function () {
let array = [1, 2, 3];
arrayHelper.move(array, 1, -2);
assert.equal(array[0], 2);
assert.equal(array[1], 1);
assert.equal(array[2], 3);
});
it('Move out of bounds to the right', function () {
let array = [1, 2, 3];
arrayHelper.move(array, 1, 4);
assert.equal(array[0], 1);
assert.equal(array[1], 3);
assert.equal(array[2], 2);
});
});