我很难弄清楚如何移动数组元素。例如,给出以下内容:
var arr = [ 'a', 'b', 'c', 'd', 'e'];
我为什么能写入移动功能'd'
之前'b'
?
还是'a'
之后'c'
?
移动后,应更新其余元素的索引。这意味着在第一个示例中,移动后arr [0] ='a',arr [1] ='d'arr [2] ='b',arr [3] ='c',arr [4] = 'e'
这似乎应该很简单,但是我无法将其包裹住。
我很难弄清楚如何移动数组元素。例如,给出以下内容:
var arr = [ 'a', 'b', 'c', 'd', 'e'];
我为什么能写入移动功能'd'
之前'b'
?
还是'a'
之后'c'
?
移动后,应更新其余元素的索引。这意味着在第一个示例中,移动后arr [0] ='a',arr [1] ='d'arr [2] ='b',arr [3] ='c',arr [4] = 'e'
这似乎应该很简单,但是我无法将其包裹住。
Moves elements within an array, returning an array containing the moved elements.
array.move(index, howMany, toIndex);
index: Index at which to move elements. If negative, index will start from the end.
howMany: Number of elements to move from index.
toIndex: Index of the array at which to place the moved elements. If negative, toIndex will start from the end.
array = ["a", "b", "c", "d", "e", "f", "g"];
array.move(3, 2, 1); // returns ["d","e"]
array; // returns ["a", "d", "e", "b", "c", "f", "g"]
Array.prototype.move || Object.defineProperty(Array.prototype, "move", {
value: function (index, howMany, toIndex) {
var
array = this,
index = parseInt(index) || 0,
index = index < 0 ? array.length + index : index,
toIndex = parseInt(toIndex) || 0,
toIndex = toIndex < 0 ? array.length + toIndex : toIndex,
toIndex = toIndex <= index ? toIndex : toIndex <= index + howMany ? index : toIndex - howMany,
moved;
array.splice.apply(array, [toIndex, 0].concat(moved = array.splice(index, howMany)));
return moved;
}
});
I ended up combining two of these to work a little better when moving both small and large distances. I get fairly consistent results, but this could probably be tweaked a little bit by someone smarter than me to work differently for different sizes, etc.
Using some of the other methods when moving objects small distances was significantly faster (x10) than using splice. This might change depending on the array lengths though, but it is true for large arrays.
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;
}
}
我需要一个不变的move方法(一个不会更改原始数组的方法),因此我修改了@Reid的可接受答案,以简单地使用Object.assign在进行拼接之前创建数组的副本。
Array.prototype.immutableMove = function (old_index, new_index) {
var copy = Object.assign([], this);
if (new_index >= copy.length) {
var k = new_index - copy.length;
while ((k--) + 1) {
copy.push(undefined);
}
}
copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
return copy;
};
这是一个jsfiddle,显示了它的作用。
可能有帮助的splice
方法Array
:https : //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice
请记住,由于它必须主动重新索引阵列,因此它可能相对昂贵。
在这里,我ECMAScript 6
基于@Merc
的答案实现了一个不变的解决方案:
const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
if (fromIndex === toIndex) return array;
const newArray = [...array];
const target = newArray[fromIndex];
const inc = toIndex < fromIndex ? -1 : 1;
for (let i = fromIndex; i !== toIndex; i += inc) {
newArray[i] = newArray[i + inc];
}
newArray[toIndex] = target;
return newArray;
};
变量名可以缩短,只需使用较长的变量名即可,以便代码可以自我解释。
您可以实现一些基本的微积分,并创建通用函数以将数组元素从一个位置移动到另一个位置。
对于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;
}
请查看“堆积物”中的“移动数组元素”以获取详细说明。
http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html
这是我的一个带有可选参数的内衬ES6解决方案on
。
if (typeof Array.prototype.move === "undefined") {
Array.prototype.move = function(from, to, on = 1) {
this.splice(to, 0, ...this.splice(from, on))
}
}
适应第一个提出的解决方案 digiguru
参数on
是from
要移动的元素的数量。
这是我在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指出的那样,在较大的数据集上它的速度明显慢。
我的2c。易于阅读,有效,快速,不会创建新数组。
function move(array, from, to) {
if( to === from ) return array;
var target = array[from];
var increment = to < from ? -1 : 1;
for(var k = from; k != to; k += increment){
array[k] = array[k + increment];
}
array[to] = target;
return array;
}
我喜欢这样 简洁明了且有效。
function arraymove(arr, fromIndex, toIndex) {
var element = arr[fromIndex];
arr.splice(fromIndex, 1);
arr.splice(toIndex, 0, element);
}
注意:请务必记住检查数组边界。
从@Reid中得到了这个想法,即在应该移动的位置上推入一些东西以保持数组大小不变。这确实简化了计算。同样,推入一个空对象还有一个额外的好处,就是以后可以唯一地搜索它。之所以可行,是因为两个对象在引用同一个对象之前是不相等的。
({}) == ({}); // false
因此,这里是接收源数组以及源索引和目标索引的函数。您可以根据需要将其添加到Array.prototype中。
function moveObjectAtIndex(array, sourceIndex, destIndex) {
var placeholder = {};
// remove the object from its initial position and
// plant the placeholder object in its place to
// keep the array length constant
var objectToMove = array.splice(sourceIndex, 1, placeholder)[0];
// place the object in the desired position
array.splice(destIndex, 0, objectToMove);
// take out the temporary object
array.splice(array.indexOf(placeholder), 1);
}