我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:
var array = [ 'a', 'b', 'c', 'd', 'e'];
我怎么能写一个函数来移动元素'd'到'b'的左边?
还是c右边的a ?
移动元素之后,应该更新其余元素的索引。结果数组将是:
array = ['a', 'd', 'b', 'c', 'e']
这看起来应该很简单,但我无法理解它。
我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:
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次重新构建数组要好得多。
其他回答
从@Reid得到这个想法,在应该被移动的项目的地方推动一些东西,以保持数组大小不变。这确实简化了计算。此外,推入空对象还有一个额外的好处,就是以后能够惟一地搜索它。这是因为两个对象在引用同一个对象之前是不相等的。
({}) == ({}); // false
这个函数接收源数组,以及源和目标索引。你可以把它添加到数组中。原型(如果需要的话)。
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);
}
在2022年,这个typescript实用程序将与单元测试一起工作。
export const arrayMove = <T>(arr: T[], fromIndex: number, toIndex: number) => {
const newArr = [...arr];
newArr.splice(toIndex, 0, newArr.splice(fromIndex, 1)[0]);
return newArr;
};
const testArray = ['1', '2', '3', '4']; description ('arrayMove', () => { it('应该将数组项移动到toIndex', () => { expect(arrayMove(testArray, 2,0))。toEqual(['3', '1', '2', '4']); expect(arrayMove(testArray, 3,1))。toEqual(['1', '4', '2', '3']); expect(arrayMove(testArray, 1,2))。toEqual(['1', '3', '2', '4']); expect(arrayMove(testArray, 0,2))。toEqual(['2', '3', '1', '4']); }); });
面向对象,可表达,可调试,无突变,已测试。
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);
});
找到并移动一个元素从第n个位置到第0个位置。
找到并移动“d”到第0个位置:
let arr = [ 'a', 'b', 'c', 'd', 'e'];
arr = [...arr.filter(item => item === 'd'), ...arr.filter(item => item !== 'd')];
我使用了@Reid这个不错的答案,但是很难将一个元素从数组的末尾移动到开头(就像在循环中一样)。 例如[a, b, c的)应该成为[' c ', ' ', ' b ']通过调用.move(2、3)
我通过改变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
};