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

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

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

还是c右边的a ?

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

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

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


当前回答

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

我不会改变数组原型。 向右移动一个项目并不会创建未定义的项目,它只是将项目移动到最右边的位置。

功能:

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

单元测试:

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

其他回答

如果你想要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)。

该方法将保留原始数组,并检查边界错误。

const move = (from, to, arr) => {
    to = Math.max(to,0)
    from > to 
        ? [].concat(
            arr.slice(0,to), 
            arr[from], 
            arr.filter((x,i) => i != from).slice(to)) 
        : to > from
            ? [].concat(
                arr.slice(0, from), 
                arr.slice(from + 1, to + 1), 
                arr[from], 
                arr.slice(to + 1))
            : arr}

在很多地方都说过(在Array.prototype中添加自定义函数)使用Array原型可能是一个坏主意,无论如何我结合了来自各种帖子的最佳内容,我使用现代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

希望对任何人都是有用的

就像所有事情一样,充分利用是最重要的。

对于单个移动,以及小型和大型数据集,这里都有完美的答案。 如果你正在做成千上万的移动,我建议你看看状态和不太频繁的密集操作。喜欢的东西:

改变你的数据集,保持对每个项目的订单“状态”。 应用数以千计的更新。 对该order属性执行单一排序。

 ["a", "b", "c"]

会改为

[
   {val: 'a', order: 0},
   {val: 'b', order: 1},
   {val: 'c', order: 2},

]

然后,应用数千次更新。

最后,根据“order”变量进行排序。 也许还要重新编号。

我还没有测试它的性能,但是可以想象,在一定的使用水平上,它比每1000次重新构建数组要好得多。

    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