/**
* 将数组 arr 中指定索引 toMoveIndexes 移动到 targetIndex 位置,targetIndex 可以是任意数字
* <h6 class="important">此函数将修改 arr 和 els, 如果希望避免原数组被修改, 请在调用此函数前复制一个新数组</h6>
*
* @param {Array} arr 任意数组
* @param {Array} toMoveIndexes 指定需要移动的索引
* @param {int }targetIndex 目标索引
* @returns {Array} 原数组
*/
export const moveIndex = (arr, toMoveIndexes, targetIndex) => {
if (targetIndex < 0) {
targetIndex = Math.max(0, targetIndex + arr.length)
}
toMoveIndexes = Array.isArray(toMoveIndexes) ? toMoveIndexes : [toMoveIndexes]
let offset = 0
const toMoveEls = toMoveIndexes.map((index, i) => {
if (index < 0) {
index = toMoveIndexes[i] = Math.max(0, index + arr.length)
}
if (index >= arr.length)
throw new Error(
`toMoveIndexes \`[${toMoveIndexes}]\` should be all included in arr indexes`,
)
if (index < targetIndex) offset++
return arr[index]
})
toMoveIndexes
.sort()
.reverse()
.forEach(index => arr.splice(index, 1))
arr.splice(targetIndex - offset, 0, ...toMoveEls)
return arr
}
const findIndex = (arr, el, key) =>
arr.findIndex(item => (key == null ? item === el : item[key] === el[key]))
/**
* 将数组 arr 中指定元素 toMoveEls 移动到 targetIndex 位置
* <h6 class="important">此函数将修改 arr 和 toMoveEls, 如果希望避免原数组被修改, 请在调用此函数前复制一个新数组</h6>
*
* @param {Array} arr 任意数组
* @param {*|Array} toMoveEls 指定需要移动的元素集合,可以是元素数组,不包含在原数组 arr 中的元素也将被添加到 arr 中
* @param {*} targetIndex 目标索引值
* @param {string} key 如果数组是对象数组,指定判断唯一性的键名称
* @returns {Array} 原数组
*/
export const moveEl2Index = (arr, toMoveEls, targetIndex, key) => {
if (targetIndex < 0) {
targetIndex = Math.max(0, targetIndex + arr.length)
}
toMoveEls = Array.isArray(toMoveEls) ? toMoveEls : [toMoveEls]
const toMoveIndexes = []
let offset = 0
toMoveEls.forEach(el => {
const index = findIndex(arr, el, key)
if (index !== -1) {
toMoveIndexes.push(index)
if (index < targetIndex) offset++
}
})
toMoveIndexes
.sort((x, y) => x - y)
.reverse()
.forEach(index => arr.splice(index, 1))
arr.splice(targetIndex - offset, 0, ...toMoveEls)
return arr
}
/**
* 将数组 arr 中指定元素 toMoveEls 移动到 targetEl 位置
* <h6 class="important">此函数将修改 arr 和 toMoveEls, 如果希望避免原数组被修改, 请在调用此函数前复制一个新数组</h6>
*
* @param {Array} arr 任意数组
* @param {*|Array} toMoveEls 指定需要移动的元素集合,可以是元素数组,不包含在原数组 arr 中的元素也将被添加到 arr 中
* @param {*} targetEl 包含在数组 arr 中的任意元素值
* @param {string} key 如果数组是对象数组,指定判断唯一性的键名称
* @param {boolean} next 插入到目标元素前方还是后方,默认插入到前方
* @throws {Error} 传入 targetEl 在 arr 中找不到时将抛出异常
* @returns {Array} 原数组
*/
export const moveEl = (arr, toMoveEls, targetEl, key, next) => {
let targetIndex = findIndex(arr, targetEl, key)
if (targetIndex === -1)
throw new Error(
`targetEl ${targetEl} should be included in arr ${arr} but not!`,
)
if (next) targetIndex++
moveEl2Index(arr, toMoveEls, targetIndex, key)
return arr
}
/**
* 将数组 arr 进行乱序输出
*
* @param {Array} arr 任意数组
* @returns {Array} 乱序数组
*/
export const shuffle = arr => {
let i = arr.length
const input = [...arr]
const output = []
while (i) {
output.push(input.splice(Math.floor(Math.random() * i--), 1)[0])
}
return output
}