开发者问题收集

将数组元素从一个数组位置移动到另一个数组位置

2011-03-15
818481

我很难弄清楚如何移动数组的元素。例如,给定以下内容:

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

我如何编写一个函数来将元素 'd' 移动到 'b' 的左侧?

或者将 'a' 移动到 'c' 的右侧?

移动元素后,其余元素的索引应更新。生成的数组将是:

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

这似乎应该很简单,但我无法理解它。

3个回答

如果您想要 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

逐步执行代码:

  1. 如果 new_index 大于数组的长度,我们希望(我推测)用新的 undefined 正确填充数组。这个小代码片段通过将 undefined 推送到数组上直到我们获得适当的长度来处理这个问题。
  2. 然后,在 arr.splice(old_index, 1)[0] 中,我们拼接出旧元素。 splice 返回拼接出的元素,但它在数组中。在我们上面的例子中,这是 [1] 。因此,我们取该数组的第一个索引,以获得原始的 1
  3. 然后我们使用 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)

Reid
2011-03-15

我喜欢这种方法,因为它很简洁,而且很有效。

579236644

注意:始终记住检查您的数组界。

以下snippet在控制台中打印一些测试,以显示 fromIndextoIndex (0..N,0..N) 工作的所有组合。 p>

在jsfiddle中运行摘要

Steak Overflow
2011-06-24

这是我在 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 指出的那样 ,它在较大的数据集上的速度明显较慢。

digiguru
2011-08-24