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

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

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

还是c右边的a ?

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

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

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


当前回答

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

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

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

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

会改为

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

]

然后,应用数千次更新。

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

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

其他回答

splice()方法的作用是:向数组中添加/从数组中删除项,并返回已删除的项。 注意:该方法会改变原始数组。/ 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"]

由于函数是可链的,这也工作:

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

演示

let ar = ['a', 'b', 'c', 'd'];

function change( old_array, old_index , new_index ){

  return old_array.map(( item , index, array )=>{
    if( index === old_index ) return array[ new_index ];
    else if( index === new_index ) return array[ old_index ];
    else return item;
  });

}

let result = change( ar, 0, 1 );

console.log( result );

结果:

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

我们可以用多种方法将数组元素从一个位置移动到另一个位置。这里我用三种方法来解决这个问题。

使用拼接移动数组元素,其中时间复杂度为二次time - O(n^2)

function arrayMove(arr, oldIndex, newIndex) {
  const copiedArr = [...arr];
  const length = copiedArr.length;
  
  if (oldIndex !== newIndex && length > oldIndex && length > newIndex) {
    copiedArr.splice(newIndex, 0, copiedArr.splice(oldIndex, 1)[0]);
  }
  
  return copiedArr;
}

arrayMove([1,2,3,4], 0, 3) // [2,3,4,1]

使用flatMap移动数组元素,其中时间复杂度为线性时间- O(n)

function arrayMove(arr, oldIndex, newIndex) {
    const length = arr.length;
    const itemToMove = arr[oldIndex]

    if (oldIndex === newIndex || oldIndex > length || newIndex > length) {
        return arr;
    }

    return arr.flatMap((item, index) => {
        if (index === oldIndex) return [];
        if (index === newIndex) return oldIndex < newIndex ? [item, itemToMove] : [itemToMove, item];
        return item;
    })
}

arrayMove([1,2,3,4], 0, 3) // [2,3,4,1]

当时间复杂度为线性时间- O(n)时,使用reduce方法移动数组元素

function arrayMove(arr, oldIndex, newIndex) {
    const length = arr.length;
    const itemToMove = arr[oldIndex]

    if (oldIndex === newIndex || oldIndex > length || newIndex > length) {
        return arr;
    }

    return arr.reduce((acc, item, index) => {
        if (index === oldIndex) return acc;
        if (index === newIndex) return oldIndex < newIndex ? [...acc, item, itemToMove] : [...acc, itemToMove, item];
        return [...acc, item];
    }, [])
}

arrayMove([1,2,3,4], 0, 3) // [2,3,4,1]

您还可以检查以下要点:将数组元素从一个数组位置移动到另一个数组位置

另一个纯JS变体使用ES6数组展开运算符,没有突变

const reorder = (array, sourceIndex, destinationIndex) => { const smallerIndex = Math.min(sourceIndex, destinationIndex); const largerIndex = Math.max(sourceIndex, destinationIndex); return [ ...array.slice(0, smallerIndex), ...(sourceIndex < destinationIndex ? array.slice(smallerIndex + 1, largerIndex + 1) : []), array[sourceIndex], ...(sourceIndex > destinationIndex ? array.slice(smallerIndex, largerIndex) : []), ...array.slice(largerIndex + 1), ]; } // returns ['a', 'c', 'd', 'e', 'b', 'f'] console.log(reorder(['a', 'b', 'c', 'd', 'e', 'f'], 1, 4))

这是基于@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);
    });
});