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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5306680/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:34:29  来源:igfitidea点击:

Move an array element from one array position to another

javascriptarrays

提问by Mark Brown

I'm having a hard time figuring out how to move an array element. For example, given the following:

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

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

How can I write a function to move 'd'before 'b'?

我怎样才能写一个函数来移动'd'之前'b'

Or 'a'after 'c'?

还是'a'之后'c'

After the move, the indices of the rest of the elements should be updated. This means in the first example after the move arr[0] would = 'a', arr[1] = 'd' arr[2] = 'b', arr[3] = 'c', arr[4] = 'e'

移动后,应更新其余元素的索引。这意味着在移动之后的第一个例子中 arr[0] will = 'a', arr[1] = 'd' arr[2] = 'b', arr[3] = 'c', arr[4] = 'e'

This seems like it should be pretty simple, but I can't wrap my head around it.

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

回答by Reid

If you'd like a version on npm, array-moveis the closest to this answer, although it's not the same implementation. See its usage section for more details. The previous version of this answer (that modified Array.prototype.move) can be found on npm at array.prototype.move.

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



I had fairly good success with this function:

我在这个功能上取得了相当不错的成功:

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

Note that the last returnis simply for testing purposes: spliceperforms operations on the array in-place, so a return is not necessary. By extension, this moveis an in-place operation. If you want to avoid that and return a copy, use slice.

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

Stepping through the code:

逐步执行代码:

  1. If new_indexis 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 undefinedon the array until we have the proper length.
  2. Then, in arr.splice(old_index, 1)[0], we splice out the old element. splicereturns 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 1there.
  3. Then we use spliceto 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.
  1. 如果new_index大于数组的长度,我们希望(我假设)用 new undefineds正确填充数组。这个小片段通过推动undefined数组直到我们有合适的长度来处理这个问题。
  2. 然后,在 中arr.splice(old_index, 1)[0],我们拼接出旧元素。splice返回拼接出来的元素,但它在一个数组中。在我们上面的例子中,这是[1]. 因此,我们采用该数组的第一个索引来获取原始数据1
  3. 然后我们用来splice在new_index 的地方插入这个元素。因为我们在 if 上面填充了数组new_index > arr.length,它可能会出现在正确的位置,除非他们做了一些奇怪的事情,比如传入一个负数。

A fancier version to account for negative indices:

一个更高级的版本来解释负指数:

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

Which should account for things like array_move([1, 2, 3], -1, -2)properly (move the last element to the second to last place). Result for that should be [1, 3, 2].

这应该说明array_move([1, 2, 3], -1, -2)正确的事情(将最后一个元素移到倒数第二个位置)。结果应该是[1, 3, 2]

Either way, in your original question, you would do array_move(arr, 0, 2)for aafter c. For dbefore b, you would do array_move(arr, 3, 1).

无论哪种方式,在您最初的问题中,您都会array_move(arr, 0, 2)aafter做c。对于d以前b,你会这样做array_move(arr, 3, 1)

回答by digiguru

Here's a one liner I found on JSPerf....

这是我在 JSPerf 上找到的一个单线......

Array.prototype.move = function(from, to) {
    this.splice(to, 0, this.splice(from, 1)[0]);
};

which is awesome to read, but if you want performance (in small data sets) try...

读起来很棒,但是如果您想要性能(在小数据集中),请尝试...

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

I can't take any credit, it should all go to Richard Scarrott. It beats the splice based method for smaller data sets in this performance test. It is however significantly slower on larger data sets as Darwayne points out.

我不能相信任何功劳,这一切都应该归功于理查德·斯卡洛特。在这个性能测试中,它在较小的数据集上击败了基于拼接的方法。然而,正如 Darwayne 指出的那样,它在较大的数据集上要慢得多。

回答by SteakOverflow

I like this way. It's concise and it works.

我喜欢这种方式。它简洁且有效。

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

Note: always remember to check your array bounds.

注意:永远记得检查你的数组边界。

Run Snippet on jsFiddle

在 jsFiddle 上运行 Snippet

回答by SteakOverflow

The splice() method adds/removes items to/from an array, and returns the removeditem(s).

Note: This method changes the original array. /w3schools/

splice() 方法向/从数组添加/删除项目,并返回删除的项目。

注意:此方法更改原始数组。/w3学校/

Array.prototype.move = function(from,to){
  this.splice(to,0,this.splice(from,1)[0]);
  return this;
};

var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(3,1);//["a", "d", "b", "c", "e"]


var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(0,2);//["b", "c", "a", "d", "e"]

as the function is chainablethis works too:

由于该功能是可链接的,因此也可以使用:

alert(arr.move(0,2).join(','));

demo here

演示在这里

回答by Merc

My 2c. Easy to read, it works, it's fast, it doesn't create new arrays.

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

回答by Anurag

Got this idea from @Reid of pushing something in the place of the item that is supposed to be moved to keep the array size constant. That does simplify calculations. Also, pushing an empty object has the added benefits of being able to search for it uniquely later on. This works because two objects are not equal until they are referring to the same object.

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

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

So here's the function which takes in the source array, and the source, destination indexes. You could add it to the Array.prototype if needed.

所以这是接收源数组和源、目标索引的函数。如果需要,您可以将它添加到 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);
}

回答by André Pena

This is based on @Reid's solution. Except:

这是基于@Reid 的解决方案。除了:

  • I'm not changing the Arrayprototype.
  • Moving an item out of bounds to the right does not create undefineditems, it just moves the item to the right-most position.
  • 我不会改变Array原型。
  • 将项目向右移出边界不会创建undefined项目,它只是将项目移动到最右侧的位置。

Function:

功能:

function move(array, oldIndex, newIndex) {
    if (newIndex >= array.length) {
        newIndex = array.length - 1;
    }
    array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
    return array;
}

Unit tests:

单元测试:

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

回答by Elie Teyssedou

Here is my one liner ES6 solutionwith an optional parameter on.

这是我的一个带有可选参数的liner ES6 解决方案on

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

Adaptation of the first solution proposed by digiguru

适应由提出的第一个解决方案 digiguru

The parameter onis the number of element starting from fromyou want to move.

该参数on是从from您要移动的元素开始的数量。

回答by Jared Updike

One approach would be to create a new array with the pieces in the order you want, using the slice method.

一种方法是使用 slice 方法按照您想要的顺序创建一个包含碎片的新数组。

Example

例子

var arr = [ 'a', 'b', 'c', 'd', 'e'];
var arr2 = arr.slice(0,1).concat( ['d'] ).concat( arr.slice(2,4) ).concat( arr.slice(4) );
  • arr.slice(0,1) gives you ['a']
  • arr.slice(2,4) gives you ['b', 'c']
  • arr.slice(4) gives you ['e']
  • arr.slice(0,1) 给你 ['a']
  • arr.slice(2,4) 给你 ['b', 'c']
  • arr.slice(4) 给你 ['e']

回答by Ken Franqueiro

The splicemethod of Arraymight help: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

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

Just keep in mind it might be relatively expensive since it has to actively re-index the array.

请记住,它可能相对昂贵,因为它必须主动重新索引数组。