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

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

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

还是c右边的a ?

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

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

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


当前回答

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

使用拼接移动数组元素,其中时间复杂度为二次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]

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

其他回答

面向对象,可表达,可调试,无突变,已测试。

class Sorter {
    sortItem(array, fromIndex, toIndex) {
        const reduceItems = () => {
            const startingItems = array.slice(0, fromIndex);
            const endingItems = array.slice(fromIndex + 1);
            return startingItems.concat(endingItems);
        }
        const addMovingItem = (movingItem, reducedItems) => {
            const startingNewItems = reducedItems.slice(0, toIndex);
            const endingNewItems = reducedItems.slice(toIndex);
            const newItems = startingNewItems.concat([movingItem]).concat(endingNewItems);
            return newItems;
        }
        const movingItem = array[fromIndex];
        const reducedItems = reduceItems();
        const newItems = addMovingItem(movingItem, reducedItems);
        return newItems;
    }
}

const sorter = new Sorter();
export default sorter;
import sorter from 'src/common/Sorter';

test('sortItem first item forward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['b', 'a', 'c', 'd'];
    expect(sorter.sortItem(startingArray, 0, 1)).toStrictEqual(expectedArray);
});
test('sortItem middle item forward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['a', 'c', 'b', 'd'];
    expect(sorter.sortItem(startingArray, 1, 2)).toStrictEqual(expectedArray);
});
test('sortItem middle item backward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['a', 'c', 'b', 'd'];
    expect(sorter.sortItem(startingArray, 2, 1)).toStrictEqual(expectedArray);
});
test('sortItem last item backward', () => {
    const startingArray = ['a', 'b', 'c', 'd'];
    const expectedArray = ['a', 'b', 'd', 'c'];
    expect(sorter.sortItem(startingArray, 3, 2)).toStrictEqual(expectedArray);
});

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

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

}

查看“移动数组元素”在“忧郁”的详细解释。

https://web.archive.org/web/20121105042534/http://www.gloommatter.com:80/DDesign/programming/moving-any-array-elements-universal-function.html

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

这里有一种方法可以用不变的方式来做。它处理负数以及一个额外的奖励。与编辑原始数组相比,这以性能为代价减少了可能的错误数量。

const numbers = [1, 2, 3];
const moveElement = (array, from, to) => {
  const copy = [...array];
  const valueToMove = copy.splice(from, 1)[0];
  copy.splice(to, 0, valueToMove);
  return copy;
};

console.log(moveElement(numbers, 0, 2))
// > [2, 3, 1]
console.log(moveElement(numbers, -1, -3))
// > [3, 1, 2] 
    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