點燈坊

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

如何將 Nested Array 轉成 String ?

Sam Xiao's Avatar 2021-04-24

實務上常遇到 API 回傳資料為 Nested Array,但卻要以 , 隔開的 String 顯示,這種常見需求該如何實現呢 ?

Version

Ramda 0.27.1

join()

import { pipe, map, lensProp, over, join } from 'ramda'

let data = [
  { title: 'FP in JavaScript',    authors: ['John', 'Kevin', 'Tom'] },
  { title: 'RxJS in Action',      authors: ['Sam' , 'Jerry', 'Ray'] },
  { title: 'Speaking JavaScript', authors: ['May' ,  'Mary', 'Jen'] },
]

pipe(
  map(x => ({
    ...x,
    authors: x.authors.join(',')
  }))
)(data) // ?

第 3 行

let data = [
  { title: 'FP in JavaScript',    authors: ['John', 'Kevin', 'Tom'] },
  { title: 'RxJS in Action',      authors: ['Sam' , 'Jerry', 'Ray'] },
  { title: 'Speaking JavaScript', authors: ['May' ,  'Mary', 'Jen'] },
]

authors 是以 Array 型態存在,但卻希望以 String 顯示。

第 9 行

pipe(
  map(x => ({
    ...x,
    authors: x.authors.join(',')
  }))
)(data) // ?

使用 pipe() 組合出 IIFE:

  • map():新資料筆數與原筆數相同,因此使用 map()
  • join():回傳仍是 Object,因此使用 arrow function 回傳 Object,authors Array 使用 Array.prototype.join(',') 轉成 String

join000

Point-free

import { pipe, map, lensProp, over, join } from 'ramda'

let data = [
  { title: 'FP in JavaScript',    authors: ['John', 'Kevin', 'Tom'] },
  { title: 'RxJS in Action',      authors: ['Sam' , 'Jerry', 'Ray'] },
  { title: 'Speaking JavaScript', authors: ['May' ,  'Mary', 'Jen'] },
]

pipe(
  map(over(lensProp('authors'), join(',')))
)(data) // ?

第 9 行

pipe(
  map(over(lensProp('authors'), join(',')))
)(data) // ?

整個關鍵在於 join(',')authors Array 轉成 String,但 join(',') 是 function 而非 value,有幾個 function 可考慮:

  • assoc():可直接修改 authors Array,但必須提供 value,因此並不適合
  • set():可直接修改 authors Array,但必須提供 value,因此並不適合
  • over():可直接修改 authors Array,但必須提供 function,因此可直接使用 join(',')

over() 需搭配 Lens,因此使用 lensProp('authors') 先建立 Lens,如此 map() 的 callback 可完全 Point-free。

join001

Conclusion

  • 很多人並不熟悉 Lens,但偏偏 over() 這個可提供 function 修改 property 的 function 僅接受 Lens,因此懂不懂 Lens 成為本文關鍵

Reference

Ramda, join()
Ramda, over()