我很难弄清楚如何移动数组中的一个元素。例如,给定以下条件:
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']
这看起来应该很简单,但我无法理解它。
当前回答
Array.move.js
总结
移动数组中的元素,返回包含已移动元素的数组。
语法
array.move(index, howMany, toIndex);
参数
index:移动元素所在的索引。如果是负数,指数将从末尾开始。
howMany:要从索引中移动的元素数量。
toIndex:移动元素所在数组的索引。如果为负,则toIndex将从末尾开始。
使用
array = ["a", "b", "c", "d", "e", "f", "g"];
array.move(3, 2, 1); // returns ["d","e"]
array; // returns ["a", "d", "e", "b", "c", "f", "g"]
Polyfill
Array.prototype.move || Object.defineProperty(Array.prototype, "move", {
value: function (index, howMany, toIndex) {
var
array = this,
index = parseInt(index) || 0,
index = index < 0 ? array.length + index : index,
toIndex = parseInt(toIndex) || 0,
toIndex = toIndex < 0 ? array.length + toIndex : toIndex,
toIndex = toIndex <= index ? toIndex : toIndex <= index + howMany ? index : toIndex - howMany,
moved;
array.splice.apply(array, [toIndex, 0].concat(moved = array.splice(index, howMany)));
return moved;
}
});
其他回答
我最终将这两种方法结合起来,以便在移动小距离和大距离时更好地工作。我得到了相当一致的结果,但这可能会被比我更聪明的人稍微调整一下,以不同的大小工作,等等。
在小距离移动对象时,使用其他一些方法明显比使用拼接快(x10)。这可能会根据数组的长度而改变,但对于大型数组是正确的。
function ArrayMove(array, from, to) {
if ( Math.abs(from - to) > 60) {
array.splice(to, 0, array.splice(from, 1)[0]);
} else {
// works better when we are not moving things very far
var target = array[from];
var inc = (to - from) / Math.abs(to - from);
var current = from;
for (; current != to; current += inc) {
array[current] = array[current + inc];
}
array[to] = target;
}
}
https://web.archive.org/web/20181026015711/https://jsperf.com/arraymove-many-sizes
一种方法是使用slice方法,按照您想要的顺序创建一个包含片段的新数组。
例子
var arr = [ 'a', 'b', 'c', 'd', 'e'];
var arr2 = arr.slice(0,1).concat( ['d'] ).concat( arr.slice(2,4) ).concat( arr.slice(4) );
Arr.slice(0,1)得到['a'] Arr.slice(2,4)给出['b', 'c'] Arr.slice(4)给出['e']
在你的例子中,因为是一个字符串数组,我们可以使用一个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.js
总结
移动数组中的元素,返回包含已移动元素的数组。
语法
array.move(index, howMany, toIndex);
参数
index:移动元素所在的索引。如果是负数,指数将从末尾开始。
howMany:要从索引中移动的元素数量。
toIndex:移动元素所在数组的索引。如果为负,则toIndex将从末尾开始。
使用
array = ["a", "b", "c", "d", "e", "f", "g"];
array.move(3, 2, 1); // returns ["d","e"]
array; // returns ["a", "d", "e", "b", "c", "f", "g"]
Polyfill
Array.prototype.move || Object.defineProperty(Array.prototype, "move", {
value: function (index, howMany, toIndex) {
var
array = this,
index = parseInt(index) || 0,
index = index < 0 ? array.length + index : index,
toIndex = parseInt(toIndex) || 0,
toIndex = toIndex < 0 ? array.length + toIndex : toIndex,
toIndex = toIndex <= index ? toIndex : toIndex <= index + howMany ? index : toIndex - howMany,
moved;
array.splice.apply(array, [toIndex, 0].concat(moved = array.splice(index, howMany)));
return moved;
}
});
我们可以用多种方法将数组元素从一个位置移动到另一个位置。这里我用三种方法来解决这个问题。
使用拼接移动数组元素,其中时间复杂度为二次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]
您还可以检查以下要点:将数组元素从一个数组位置移动到另一个数组位置