若要從 Array 擷取其中一部分,但我們無法如 slice()
指定要的部分,只能指定不要的部分,此時我們可使用 Ramda 的 remove()
。
Version
macOS Mojave 10.15.1
VS Code 1.40.2
Quokka 1.0.262
Ramda 0.26.1
Imperative
let data = [1, 2, 3, 4]
let remove = begin => cnt => arr => {
let result = []
let end = begin + cnt
for(let i = 0; i < arr.length; i++) {
if (i >= begin && i < end) continue
else result.push(arr[i])
}
return result
}
remove(1)(2)(data) // ?
data // ?
Imperative 可先將 end index 計算好,當 for
loop 的 index 在 begin
與 end
區間時就 continue
不處理,否則 push 進要回傳的 result
array。
Array.prototype.splice()
let data = [1, 2, 3, 4]
let remove = begin => count => arr => {
let result = arr.slice()
result.splice(begin, count)
return result
}
remove(1)(2)(data) // ?
data // ?
Array.prototype.splice()
是很強的 method,可用來對 array 處理 insert、update 與 delete,因此 remove()
也可改用 splice()
實踐,唯 splice()
有很大 side effect,須小心使用。
因此比較好的作法是使用 slice()
將傳進 array 再 clone 一份 result
出來,再針對 result
做 splice()
處理。
Functional
import { slice, without } from 'ramda'
let data = [1, 2, 3, 4]
let remove = begin => cnt => arr => without(
slice(begin)(begin + cnt)(arr)
)(arr)
remove(1)(2)(data) // ?
data // ?
假如我們一開始不知道 Ramda 的 remove()
,也可透過 slice()
與 without()
組合:
- 先使用
slice()
找出不要的部分 - 再使用
without()
排除不要的部分
Point-free
import { slice, without, chain } from 'ramda'
let data = [1, 2, 3, 4]
let remove = begin => cnt => chain(
without,
slice(begin)(begin + cnt)
)
remove(1)(2)(data) // ?
data // ?
也可以進一步 point-free,使用 chain()
將 without()
與 slice()
整合起來,一目瞭然。
Ramda
import { remove } from 'ramda'
let data = [1, 2, 3, 4]
remove(1)(2)(data) // ?
data // ?
事實上 Ramda 已經內建 remove()
,可直接使用。
remove()
Number → Number → [a] → [a]
直接指定 Array 中不要的部分擷取部分 Array
Number
:Array 的 start index
Number
:Array 的 element count
[a]
:Data 為 array
[a]
:回傳所截取的 array
Conclusion
Array.prototype.splice()
雖然好用,但要小心其 side effect,必須先用slice()
clone 一份出來再使用remove()
是與slice()
相對的 function:slice()
是指定要的部分,而remove()
是指定不要的部分
Reference
MDN, Array.prototype.splice()
Ramda, remove()
Ramda, slice()
Ramda, without()