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

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

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

还是c右边的a ?

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

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

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


当前回答

如果你想要npm上的一个版本,array-move是最接近这个答案的,尽管它不是相同的实现。更多细节请参见其用法部分。这个答案的前一个版本(修改了Array.prototype.move)可以在npm的Array.prototype.move中找到。


我在这个函数上做得相当成功:

函数array_move(arr, old_index, new_index) { If (new_index >= arr.length) { Var k = new_index - arr。长度+ 1; 当(k——){ arr.push(定义); } } 加勒比海盗。拼接(new_index, 0, arr.)拼接(old_index, 1) [0]); 返回arr;//用于测试 }; //返回[2,1,3] Console.log (array_move([1,2,3], 0,1));

请注意,最后一个返回值只是用于测试目的:splice在原地对数组执行操作,因此不需要返回值。通过扩展,这个动作是一个原地操作。如果你想避免这种情况并返回一个副本,请使用slice。

逐步执行代码:

If new_index is greater than the length of the array, we want (I presume) to pad the array properly with new undefineds. This little snippet handles this by pushing undefined on the array until we have the proper length. Then, in arr.splice(old_index, 1)[0], we splice out the old element. splice returns the element that was spliced out, but it's in an array. In our above example, this was [1]. So we take the first index of that array to get the raw 1 there. Then we use splice to insert this element in the new_index's place. Since we padded the array above if new_index > arr.length, it will probably appear in the right place, unless they've done something strange like pass in a negative number.

解释负指数的一个更花哨的版本:

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

其他回答

下面是我的一行ES6解决方案,带有一个可选参数。

if (typeof Array.prototype.move === "undefined") {
  Array.prototype.move = function(from, to, on = 1) {
    this.splice(to, 0, ...this.splice(from, on))
  }
}

digiguru提出的第一个解决方案的改编

on的参数是你想要移动的元素个数。

这里有一个可链接的变化:

if (typeof Array.prototype.move === "undefined") {
  Array.prototype.move = function(from, to, on = 1) {
    return this.splice(to, 0, ...this.splice(from, on)), this
  }
}

[3, 4, 5, 1, 2].move(3, 0, 2) // => [1, 2, 3, 4, 5]

如果你想避免原型污染,这里有一个独立的函数:

function move(array, from, to, on = 1) {
  return array.splice(to, 0, ...array.splice(from, on)), array
}

move([3, 4, 5, 1, 2], 3, 0, 2) // => [1, 2, 3, 4, 5]

最后,这是一个不会改变原始数组的纯函数:

function moved(array, from, to, on = 1) {
  return array = array.slice(), array.splice(to, 0, ...array.splice(from, on)), array
}

这应该涵盖了其他答案中出现的所有变化。

从@Reid得到这个想法,在应该被移动的项目的地方推动一些东西,以保持数组大小不变。这确实简化了计算。此外,推入空对象还有一个额外的好处,就是以后能够惟一地搜索它。这是因为两个对象在引用同一个对象之前是不相等的。

({}) == ({}); // false

这个函数接收源数组,以及源和目标索引。你可以把它添加到数组中。原型(如果需要的话)。

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

一种方法是使用splice()从数组中删除项,然后再次使用splice()方法将删除的项插入到目标索引中。

Const array = ['a', 'b', 'c', 'd', 'e'] const newArray = moveItem(array, 3,1) //将元素从索引3移动到索引1 函数moveItem(arr, fromIndex, toIndex){ let itemRemoved = arr。splice(fromIndex, 1) //将删除的项赋值为数组 加勒比海盗。splice(toIndex, 0, itemRemoved[0]) //将itemRemoved插入目标索引 返回加勒比海盗 } console.log (newArray)

我喜欢这样。它简洁而有效。

function arraymove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
}

注意:总是记得检查你的数组边界。

在jsFiddle中运行Snippet

下面是我在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指出的那样,在较大的数据集上,它要慢得多。