點燈坊

失くすものさえない今が強くなるチャンスよ

使用 remove() 指定 Array 中不要部分

Sam Xiao's Avatar 2019-12-08

若要從 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 在 beginend 區間時就 continue 不處理,否則 push 進要回傳的 result array。

remove000

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 出來,再針對 resultsplice() 處理。

remove001

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() 排除不要的部分

remove002

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() 整合起來,一目瞭然。

remove003

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

remove004

Conclusion

  • Array.prototype.splice() 雖然好用,但要小心其 side effect,必須先用 slice() clone 一份出來再使用
  • remove() 是與 slice() 相對的 function:slice() 是指定要的部分,而 remove() 是指定不要的部分

Reference

MDN, Array.prototype.splice()
Ramda, remove()
Ramda, slice()
Ramda, without()