點燈坊

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

使用 update() 改變 Array 中指定 Index 值

Sam Xiao's Avatar 2019-12-08

若要改變 Array 中指定 Index 值,Ramda 提供了 update(),可自行傳入 Index 與 Value 改變之。

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]

let update = idx => val => arr => {
  let result = arr.slice()
  result[idx] = val
  return result
}
  
update(1)(4)(data) // ?
data // ?

update() 最直覺會使用 [] 直接改變 array,但別忘了 function 對於 array 與 object 是 pass by reference,因此直接修改 argument 相當於也修改了原始 data,有嚴重 side effect。

因此比較好的作法是使用 slice() 將傳進 array 再 clone 一份 result 出來,再針對 result[] 處理。

update000

let data = [1, 2, 3]

let update = idx => val => arr => {
  let result = []

  for(let i = 0; i < arr.length; i++) {
    if (i === idx) result[i] = val
    else result[i] = arr[i]
  }

  return result
}
  
update(1)(4)(data) // ?
data // ?

比較好的做法是另外建立回傳的 result array,乖乖使用 for loop 判斷 index 並改變其 value,如此就不會有 side effect。

update001

Array.prototype.reduce()

let data = [1, 2, 3]

let update = idx => val => arr => arr.reduce((a, x, i) =>
  i === idx ? [...a, val] : [...a, x]
, [])
  
update(1)(4)(data) // ?
data // ?

回傳是單一 array 且可用 for loop 實現,就可改用 reduce() 改寫,且也沒有 side effect。

別忘了 reduce() 的第三個 parameter 為 index,因此可用來判斷指定 index。

update002

Array.prototype.splice()

let data = [1, 2, 3]

let update = idx => val => arr => {
  let result = arr.slice()
  result.splice(idx, 1, val)
  return result
}

update(1)(4)(data) // ?
data //

Array.prototype.splice() 是很強的 method,可用來對 array 處理 insert、update 與 delete,因此 update() 也可改用 splice() 實踐,唯 splice() 有很大 side effect,須小心使用。

因此比較好的作法是使用 slice() 將傳進 array 再 clone 一份 result 出來,再針對 resultsplice() 處理。

update003

Ramda

import { update } from 'ramda'

let data = [1, 2, 3]

update(1)(4)(data) // ?
data // ?

Ramda 提供了 update(),可直接使用,且沒有 side effect。

update()
Number → a → [a] → [a]
使用 value 改變 array 中指定 index 值

Number:指定 index 值

a:改變 index 的 value

[a]:data 為 array

[a]:回傳改變過 array

update004

Conclusion

  • Array.prototype.splice() 雖然好用,但要小心其 side effect,必須先用 slice() clone 一份出來再使用
  • adjust()update() 很類似,唯 adjust() 傳入 function,而 update() 傳入 value

Reference

MDN, Array.prototype.reduce()
MDN, Array.prototype.splice()
MDN, Array.prototype.slice()
Ramda, update()