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

时间:2021-10-07 21:26:00

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'?

我怎么写一个函数在b之前移动d ?

Or 'a' after 'c'?

或“c”后“a”吗?

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]之后的第一个例子中[0]= 'a', arr[1] = 'd' r[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.

这看起来应该很简单,但是我不能把我的头围起来。

17 个解决方案

#1


489  

If you'd like a version on npm, array-move is 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上有一个版本,arraymove是最接近这个答案的,尽管它不是同一个实现。有关更多细节,请参见其使用部分。这个答案的前一个版本(修改后的Array.prototype.move)可以在Array.prototype.move的npm找到。


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 return is simply for testing purposes: splice performs operations on the array in-place, so a return is not necessary. By extension, this move is an in-place operation. If you want to avoid that and return a copy, use slice.

请注意,最后的返回只是为了测试目的:splice在数组内执行操作,因此没有必要返回。通过扩展,这是一个就地操作。如果您想要避免这种情况并返回一个副本,请使用slice。

Stepping through the code:

步进通过代码:

  1. 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.
  2. 如果new_index大于数组的长度,我们希望(我假定)用新的未定义的数组适当地填充数组。这个小代码段通过在数组中按未定义的方式来处理这个问题,直到我们有合适的长度为止。
  3. 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.
  4. 然后,在加勒比海盗。splice(old_index, 1)[0],我们将原来的元素拼接起来。splice返回被拼接的元素,但它位于数组中。在上面的例子中,这是[1]。所以我们取这个数组的第一个索引来得到原始的1。
  5. 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.
  6. 然后,我们使用splice在new_index的位置插入这个元素。因为我们在new_index > arr上添加了数组。长度,它可能会出现在正确的地方,除非他们做了一些奇怪的事情,比如传递一个负数。

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 a after c. For d before b, you would do array_move(arr, 3, 1).

不管怎样,在你最初的问题中,你会在a之后做array_move(arr, 0,2),在b之前,你会做array_move(arr, 3,1)。

#2


187  

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.

我不能相信,这一切都应该交给Richard Scarrott。在这个性能测试中,它击败了基于splice的小数据集方法。然而,正如Darwayne指出的那样,在大数据集上它的速度要慢得多。

#3


105  

I like this way. It works, it's quick and elegant.

我喜欢这种方式。它很好用,又快又优雅。

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.

注意:一定要记得检查数组的范围。

#4


25  

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

splice()方法添加/移除数组中的项,并返回被删除的项。

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

注意:此方法更改原始数组。/ w3schools /

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 chainable this works too:

由于这个函数是可链的,所以也可以这样做:

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

demo here

演示

#5


18  

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

我的2摄氏度。很容易阅读,它是有效的,它是快速的,它不会创建新的数组。

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

#6


14  

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.

这是获取源数组的函数,以及源,目标索引。你可以把它添加到数组中。如果需要样机。

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

#7


13  

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

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

  • I'm not changing the Array prototype.
  • 我不会改变数组的原型。
  • Moving an item out of bounds to the right does not create undefined items, it just moves the item to the right-most position.
  • 将一个项目从边界移到右边不会创建未定义的项,它只是将项移动到最右边的位置。

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

#8


7  

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(0,1)给你[a]
  • arr.slice(2,4) gives you ['b', 'c']
  • arr.slice(2,4)给你['b', 'c']
  • arr.slice(4) gives you ['e']
  • arr.slice(4)给你(“e”)

#9


6  

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

数组的splice方法可能会有所帮助:https://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.

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

#10


6  

You can implement some basic Calculus and create a universal function for moving array element from one position to the other.

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

For JavaScript it looks like this:

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

}

Check out "moving array elements" at "gloommatter" for detailed explanation.

在“gloommatter”中查看“移动数组元素”以获得详细解释。

http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html

http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html

#11


5  

I needed an immutable move method (one that didn't change the original array), so I adapted @Reid's accepted answer to simply use Object.assign to create a copy of the array before doing the splice.

我需要一个不可变的移动方法(一个没有改变原始数组的方法),所以我调整了@Reid的被接受的答案来简单地使用对象。在进行拼接之前,指定创建一个数组的副本。

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

Here is a jsfiddle showing it in action.

这是一个显示它在行动中的jsfiddle。

#12


4  

    Array.prototype.moveUp = function (value, by) {
        var index = this.indexOf(value),
            newPos = index - (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos < 0)
            newPos = 0;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };

    Array.prototype.moveDown = function (value, by) {
        var index = this.indexOf(value),
            newPos = index + (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos >= this.length)
            newPos = this.length;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };



    var arr = ['banana', 'curyWurst', 'pc', 'remembaHaruMembaru'];

    alert('withiout changes= '+arr[0]+' ||| '+arr[1]+' ||| '+arr[2]+' ||| '+arr[3]);
    arr.moveDown(arr[2]);


    alert('third word moved down= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);
    arr.moveUp(arr[2]);
    alert('third word moved up= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview

#13


2  

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.

toIndex:用来放置移动元素的数组的索引。如果是负数,那么toIndex将从最后开始。

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

#14


2  

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.

在移动物体时,使用一些其他的方法比使用splice要快得多(x10)。这可能会根据数组的长度而变化,但是对于大型数组来说也是如此。

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

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

#15


1  

I used the nice answer of @Reid, but struggled with moving an element from the end of an array one step further - to the beginning (like in a loop). E.g. ['a', 'b', 'c'] should become ['c', 'a', 'b'] by calling .move(2,3)

我使用了@Reid的漂亮的答案,但是在将一个元素从数组的末尾移动到开始(比如在一个循环中)时,我一直在挣扎。例如[a,b,c的)应该成为[' c ',' ',' b ']通过调用.move(2、3)

I achieved this by changing the case for new_index >= this.length.

我通过改变new_index >= this。length来实现这一点。

Array.prototype.move = function (old_index, new_index) {
        console.log(old_index + " " + new_index);
        while (old_index < 0) {
            old_index += this.length;
        }
        while (new_index < 0) {
            new_index += this.length;
        }
        if (new_index >= this.length) {
            new_index = new_index % this.length;
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this; // for testing purposes
    };

#16


1  

I've implemented an immutable ECMAScript 6 solution based off of @Merc's answer over here:

我已经实现了一个不可变的ECMAScript 6解决方案,基于@Merc的回答:

const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
  const newArray = [...array];

  if (fromIndex === toIndex) return newArray;

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

The variable names can be shortened, just used long ones so that the code can explain itself.

变量名称可以缩短,只需使用长时间的名称,这样代码就可以解释自己。

#17


0  

It is stated in many places (adding custom functions into Array.prototype) playing with the Array prototype could be a bad idea, anyway I combined the best from various posts, I came with this, using modern Javascript:

它在很多地方都有说明(在Array.prototype中添加定制函数)和数组原型一起玩可能是个坏主意,不管怎样,我把最好的从不同的帖子中结合起来,我使用了现代的Javascript:

    Object.defineProperty(Array.prototype, 'immutableMove', {
        enumerable: false,
        value: 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
        }
    });

    //how to use it
    myArray=[0, 1, 2, 3, 4];
    myArray=myArray.immutableMove(2, 4);
    console.log(myArray);
    //result: 0, 1, 3, 4, 2

Hope can be useful to anyone

希望对任何人都有用。

#1


489  

If you'd like a version on npm, array-move is 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上有一个版本,arraymove是最接近这个答案的,尽管它不是同一个实现。有关更多细节,请参见其使用部分。这个答案的前一个版本(修改后的Array.prototype.move)可以在Array.prototype.move的npm找到。


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 return is simply for testing purposes: splice performs operations on the array in-place, so a return is not necessary. By extension, this move is an in-place operation. If you want to avoid that and return a copy, use slice.

请注意,最后的返回只是为了测试目的:splice在数组内执行操作,因此没有必要返回。通过扩展,这是一个就地操作。如果您想要避免这种情况并返回一个副本,请使用slice。

Stepping through the code:

步进通过代码:

  1. 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.
  2. 如果new_index大于数组的长度,我们希望(我假定)用新的未定义的数组适当地填充数组。这个小代码段通过在数组中按未定义的方式来处理这个问题,直到我们有合适的长度为止。
  3. 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.
  4. 然后,在加勒比海盗。splice(old_index, 1)[0],我们将原来的元素拼接起来。splice返回被拼接的元素,但它位于数组中。在上面的例子中,这是[1]。所以我们取这个数组的第一个索引来得到原始的1。
  5. 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.
  6. 然后,我们使用splice在new_index的位置插入这个元素。因为我们在new_index > arr上添加了数组。长度,它可能会出现在正确的地方,除非他们做了一些奇怪的事情,比如传递一个负数。

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 a after c. For d before b, you would do array_move(arr, 3, 1).

不管怎样,在你最初的问题中,你会在a之后做array_move(arr, 0,2),在b之前,你会做array_move(arr, 3,1)。

#2


187  

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.

我不能相信,这一切都应该交给Richard Scarrott。在这个性能测试中,它击败了基于splice的小数据集方法。然而,正如Darwayne指出的那样,在大数据集上它的速度要慢得多。

#3


105  

I like this way. It works, it's quick and elegant.

我喜欢这种方式。它很好用,又快又优雅。

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.

注意:一定要记得检查数组的范围。

#4


25  

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

splice()方法添加/移除数组中的项,并返回被删除的项。

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

注意:此方法更改原始数组。/ w3schools /

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 chainable this works too:

由于这个函数是可链的,所以也可以这样做:

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

demo here

演示

#5


18  

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

我的2摄氏度。很容易阅读,它是有效的,它是快速的,它不会创建新的数组。

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

#6


14  

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.

这是获取源数组的函数,以及源,目标索引。你可以把它添加到数组中。如果需要样机。

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

#7


13  

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

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

  • I'm not changing the Array prototype.
  • 我不会改变数组的原型。
  • Moving an item out of bounds to the right does not create undefined items, it just moves the item to the right-most position.
  • 将一个项目从边界移到右边不会创建未定义的项,它只是将项移动到最右边的位置。

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

#8


7  

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(0,1)给你[a]
  • arr.slice(2,4) gives you ['b', 'c']
  • arr.slice(2,4)给你['b', 'c']
  • arr.slice(4) gives you ['e']
  • arr.slice(4)给你(“e”)

#9


6  

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

数组的splice方法可能会有所帮助:https://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.

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

#10


6  

You can implement some basic Calculus and create a universal function for moving array element from one position to the other.

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

For JavaScript it looks like this:

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

}

Check out "moving array elements" at "gloommatter" for detailed explanation.

在“gloommatter”中查看“移动数组元素”以获得详细解释。

http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html

http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-function.html

#11


5  

I needed an immutable move method (one that didn't change the original array), so I adapted @Reid's accepted answer to simply use Object.assign to create a copy of the array before doing the splice.

我需要一个不可变的移动方法(一个没有改变原始数组的方法),所以我调整了@Reid的被接受的答案来简单地使用对象。在进行拼接之前,指定创建一个数组的副本。

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

Here is a jsfiddle showing it in action.

这是一个显示它在行动中的jsfiddle。

#12


4  

    Array.prototype.moveUp = function (value, by) {
        var index = this.indexOf(value),
            newPos = index - (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos < 0)
            newPos = 0;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };

    Array.prototype.moveDown = function (value, by) {
        var index = this.indexOf(value),
            newPos = index + (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos >= this.length)
            newPos = this.length;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };



    var arr = ['banana', 'curyWurst', 'pc', 'remembaHaruMembaru'];

    alert('withiout changes= '+arr[0]+' ||| '+arr[1]+' ||| '+arr[2]+' ||| '+arr[3]);
    arr.moveDown(arr[2]);


    alert('third word moved down= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);
    arr.moveUp(arr[2]);
    alert('third word moved up= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview

#13


2  

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.

toIndex:用来放置移动元素的数组的索引。如果是负数,那么toIndex将从最后开始。

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

#14


2  

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.

在移动物体时,使用一些其他的方法比使用splice要快得多(x10)。这可能会根据数组的长度而变化,但是对于大型数组来说也是如此。

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

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

#15


1  

I used the nice answer of @Reid, but struggled with moving an element from the end of an array one step further - to the beginning (like in a loop). E.g. ['a', 'b', 'c'] should become ['c', 'a', 'b'] by calling .move(2,3)

我使用了@Reid的漂亮的答案,但是在将一个元素从数组的末尾移动到开始(比如在一个循环中)时,我一直在挣扎。例如[a,b,c的)应该成为[' c ',' ',' b ']通过调用.move(2、3)

I achieved this by changing the case for new_index >= this.length.

我通过改变new_index >= this。length来实现这一点。

Array.prototype.move = function (old_index, new_index) {
        console.log(old_index + " " + new_index);
        while (old_index < 0) {
            old_index += this.length;
        }
        while (new_index < 0) {
            new_index += this.length;
        }
        if (new_index >= this.length) {
            new_index = new_index % this.length;
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this; // for testing purposes
    };

#16


1  

I've implemented an immutable ECMAScript 6 solution based off of @Merc's answer over here:

我已经实现了一个不可变的ECMAScript 6解决方案,基于@Merc的回答:

const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
  const newArray = [...array];

  if (fromIndex === toIndex) return newArray;

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

The variable names can be shortened, just used long ones so that the code can explain itself.

变量名称可以缩短,只需使用长时间的名称,这样代码就可以解释自己。

#17


0  

It is stated in many places (adding custom functions into Array.prototype) playing with the Array prototype could be a bad idea, anyway I combined the best from various posts, I came with this, using modern Javascript:

它在很多地方都有说明(在Array.prototype中添加定制函数)和数组原型一起玩可能是个坏主意,不管怎样,我把最好的从不同的帖子中结合起来,我使用了现代的Javascript:

    Object.defineProperty(Array.prototype, 'immutableMove', {
        enumerable: false,
        value: 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
        }
    });

    //how to use it
    myArray=[0, 1, 2, 3, 4];
    myArray=myArray.immutableMove(2, 4);
    console.log(myArray);
    //result: 0, 1, 3, 4, 2

Hope can be useful to anyone

希望对任何人都有用。