我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:
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']
这看起来应该很简单,但我无法理解它。
当前回答
面向对象,可表达,可调试,无突变,已测试。
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);
});
其他回答
下面是我的一行ES6解决方案,带有一个可选参数。
if (typeof Array.prototype.move === "undefined") {
Array.prototype.move = function(from, to, on = 1) {
this.splice(to, 0, ...this.splice(from, on))
}
}
digiguru提出的第一个解决方案的改编
on的参数是你想要移动的元素个数。
这里有一个可链接的变化:
if (typeof Array.prototype.move === "undefined") {
Array.prototype.move = function(from, to, on = 1) {
return this.splice(to, 0, ...this.splice(from, on)), this
}
}
[3, 4, 5, 1, 2].move(3, 0, 2) // => [1, 2, 3, 4, 5]
如果你想避免原型污染,这里有一个独立的函数:
function move(array, from, to, on = 1) {
return array.splice(to, 0, ...array.splice(from, on)), array
}
move([3, 4, 5, 1, 2], 3, 0, 2) // => [1, 2, 3, 4, 5]
最后,这是一个不会改变原始数组的纯函数:
function moved(array, from, to, on = 1) {
return array = array.slice(), array.splice(to, 0, ...array.splice(from, on)), array
}
这应该涵盖了其他答案中出现的所有变化。
您可以实现一些基本的演算,并创建一个通用函数来将数组元素从一个位置移动到另一个位置。
对于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
在你的例子中,因为是一个字符串数组,我们可以使用一个ranking对象来重新排列字符串数组:
let rank = { 'a': 0, 'b': 1, 'c': 2, 'd': 0.5, 'e': 4 };
arr.sort( (i, j) => rank[i] - rank[j] );
我们可以使用这种方法来编写一个move函数,它工作在字符串数组上:
函数stringArrayMove(from, to) { 令rank = arr。Reduce ((p, c, i) => (p [c] = i, p), ({})); / /等级= {a: 0,“b”:1、“c”:2,' d ': 3,“e”:4} Rank [arr[from]] = - 0.5; / /等级= {a: 0,“b”:1、“c”:2,' d ': 1.5,“e”:4} 加勒比海盗。排序((i, j) => rank[i] - rank[j]); // arr = ['a', 'd', 'b', 'c', 'e']; } Let arr = ['a', 'b', 'c', 'd', 'e']; stringArrayMove(arr, 3,1); console.log(JSON.stringify(arr));
然而,如果我们想要排序的是一个对象数组,我们可以将排序作为每个对象的新属性,即。
let arr = [ { value: 'a', rank: 0 },
{ value: 'b', rank: 1 },
{ value: 'c', rank: 2 },
{ value: 'd', rank: 0.5 },
{ value: 'e', rank: 4 } ];
arr.sort( (i, j) => i['rank'] - j['rank'] );
我们可以使用Symbol来隐藏这个属性的可见性,即它不会在JSON.stringify中显示。我们可以在objectArrayMove函数中泛化它:
function objectArrayMove(arr, from, to) { let rank = Symbol("rank"); arr.forEach( (item, i) => item[rank] = i ); arr[from][rank] = to - 0.5; arr.sort( (i, j) => i[rank] - j[rank]); } let arr = [ { value: 'a' }, { value: 'b' }, { value: 'c' }, { value: 'd' }, { value: 'e' } ]; console.log( 'array before move: ', JSON.stringify( arr ) ); // array before move: [{"value":"a"},{"value":"b"},{"value":"c"},{"value":"d"},{"value":"e"}] objectArrayMove(arr, 3, 1); console.log( 'array after move: ', JSON.stringify( arr ) ); // array after move: [{"value":"a"},{"value":"d"},{"value":"b"},{"value":"c"},{"value":"e"}]
作为里德精彩回答的补充(因为我无法评论); 你可以使用模数来让负标和过大的下标“滚动”:
函数array_move(arr, old_index, new_index) { New_index =((New_index % arr.length) + arr.length) % arr.length; 加勒比海盗。拼接(new_index, 0, arr.)拼接(old_index, 1) [0]); 返回arr;//用于测试 } //返回[2,1,3] Console.log (array_move([1,2,3], 0,1));
如果对象是嵌套的:
let array = ['a', 'b', 'c', 'd', 'e'];
let existingElement = JSON.parse(JSON.stringify(array[3]));
array.splice(1, 0, existingElement);
array.splice(4, 1);
console.log(array)