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

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

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'

这似乎应该很简单,但是我无法将其包裹住。

Mandy村村Harry2020/03/12 17:46:57

    let oldi, newi, arr;
    
    if(newi !== oldi) {
      let el = this.arr.splice(oldi, 1);
      if(newi > oldi && newi === (this.arr.length + 2)) {
        this.arr.push("");
      }
      this.arr.splice(newi, 0, el);
      if(newi > oldi && newi === (this.arr.length + 2)) {
        this.arr.pop();
      }
    }

神无LEY2020/03/12 17:46:57

Array.move.js

Summary

Moves elements within an array, returning an array containing the moved elements.

Syntax

array.move(index, howMany, toIndex);

Parameters

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.

Usage

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"]

Polyfill

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;
    }
});
Eva猿2020/03/12 17:46:57

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

http://jsperf.com/arraymove-many-sizes

樱泡芙2020/03/12 17:46:57

我需要一个不变的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,显示了它的作用

村村A2020/03/12 17:46:57

可能有帮助splice方法Arrayhttps : //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

请记住,由于它必须主动重新索引阵列,因此它可能相对昂贵。

Green老丝Itachi2020/03/12 17:46:56

在这里,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;
};

变量名可以缩短,只需使用较长的变量名即可,以便代码可以自我解释。

樱神无2020/03/12 17:46:56

您可以实现一些基本的微积分,并创建通用函数以将数组元素从一个位置移动到另一个位置。

对于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

猪猪阳光2020/03/12 17:46:56

这是我的一个带有可选参数的内衬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

参数onfrom要移动的元素的数量

Gil小哥伽罗2020/03/12 17:46:56

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

TomL2020/03/12 17:46:56

我的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;
}
神乐Green2020/03/12 17:46:56

我喜欢这样 简洁明了且有效。

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

注意:请务必记住检查数组边界。

在jsFiddle上运行代码段

Tony樱番长2020/03/12 17:46:56

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