1. 背景
    1. 简单的考虑
  2. 简写

一路向西

可以了,谢谢,只是有点伤感。

背景

假设有这样一个数组

[1,2,3,4,5]
现在想要左移或者右移N位,比如移动1位

//左移1位
[2,3,4,5,1]

//右移1位
[5,1,2,3,4]

简单的考虑

  • 把数组 arr 看成循环数组
  • 正确处理数组 range{0, arr.length} 外的索引
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//- 通过 from_index 和 max_index 来计算出移动后位置对应的初始位置,
//- 这里考虑 from_index 可能为大于 max_index 或者 小于 0 的值.
function from_pos (from_index, max_index) {
return from_index > max_index ?
(from_index - 1 - max_index) :
(from_index < 0 ? 1 : 0) * max_index + from_index
}

function leftDisplacement (list, n = 0) {
//- n 的绝对值可能远超 arr.length, 先进行取余
n = n % list.length
//- 如果 n 为负值, 则其含义为"右移", 我们须将其转化为对应的"左移"值
n = n < 0 ? list.length + n : n

return list.map((val, index, arr) => {
//- 调用 from_pos 计算出每个 index 对应的 from_index = index + n 上的值
return arr[from_pos(index + n, arr.length - 1)]
})
}

console.log('[leftDisplacement.test] 0', leftDisplacement([0, 1, 2, 3, 4]))
console.log('[leftDisplacement.test] 2', leftDisplacement([0, 1, 2, 3, 4], 2))
console.log('[leftDisplacement.test] -2', leftDisplacement([0, 1, 2, 3, 4], -2))

以下为输出结果

  

简写

有没有形式上更简单的实现方式呢?毕竟写两个函数实在太 "nodejs" 了, 我们注意到Array.prototype.slice这个方法的两个参数beginend都支持负整数.

对于 begin 而言
A negative index can be used, indicating an offset from the end of the sequence. slice(-2) extracts the last two elements in the sequence.

负值的 index 表示从序列的末尾开始计算的偏移量.slice(-2)会截取出在序列的最后两个元素.

对于 end 而言
A negative index can be used, indicating an offset from the end of the sequence. slice(2,-1) extracts the third element through the second-to-last element in the sequence.

负值的 index 表示从序列的末尾开始计算的偏移量.slice(2, -1)会截取出序列的 [2, ARR_LEN - 1) 子序列

这意味着我们上述考虑中对from_pos的调用可以发生一些变化.

只考虑 n 为正整数的情况, 则有

  • list.slice(-n)取数组后 n 个元素组成的序列
  • list.slice(0, -n)取数组 [0, list.length-n) 子序列 subseq2
  • subseq2.concat(subseq1)即为结果数组

n 为负整数的情况可转化为 n 为正整数的情况

n 为 0, 则不必位移

1
2
3
4
5
6
7
8
function leftDisplacement (list, n = 0) {
n = n % list.length
return !n ? list : list.slice(-n).concat(list.slice(0, -n))
}

console.log('[leftDisplacement.test] 0', leftDisplacement([0, 1, 2, 3, 4]))
console.log('[leftDisplacement.test] 2', leftDisplacement([0, 1, 2, 3, 4], 2))
console.log('[leftDisplacement.test] -2', leftDisplacement([0, 1, 2, 3, 4], -2))

进一步简化一下, 写出一行流

experimenet-one-step.jsview raw
1
2
3
function leftDisplacement (list, n = 0) {
return (n = n % list.length, !n ? list : list.slice(-n).concat(list.slice(0, -n)))
}
(完)
首页归档简历