實務上常遇到 API 回傳資料為 Nested Object Array,但卻要以 ,
隔開的 String 顯示,這種常見需求該如何實現呢 ?
Version
Ramda 0.27.1
map()
import { pipe, map } from 'ramda'
let data = [
{
title: 'FP in JavaScript',
authors: [
{ name: 'John'},
{ name: 'Kevin'},
{ name: 'Tom'}
] },
{
title: 'RxJS in Action',
authors: [
{ name: 'Sam' },
{ name: 'Jerry' },
{ name: 'Ray' }
]
},
{
title: 'Speaking JavaScript',
authors: [
{ name: 'May'},
{ name: 'Mary'},
{ name: 'Jen'}
]
}
]
pipe(
map(x => ({
title: x.title,
authors: x.authors.map(x => x.name)
})),
map(x => ({
title: x.title,
authors: x.authors.join(',')
}))
)(data) // ?
第 3 行
let data = [
{
title: 'FP in JavaScript',
authors: [
{ name: 'John'},
{ name: 'Kevin'},
{ name: 'Tom'}
] },
{
title: 'RxJS in Action',
authors: [
{ name: 'Sam' },
{ name: 'Jerry' },
{ name: 'Ray' }
]
},
{
title: 'Speaking JavaScript',
authors: [
{ name: 'May'},
{ name: 'Mary'},
{ name: 'Jen'}
]
}
]
authors
是以 Object Array 型態存在,但卻希望以 String 顯示。
分兩階段處理:
- 先將 Object Array 轉成 Array
- 再將 Array 轉成 String
30 行
map(x => ({
title: x.title,
authors: x.authors.map(x => x.name)
})),
map()
:在map()
中再使用Array.prototype.map()
取出 Object Array 中的name
成為單純 Array。
34 行
map(x => ({
title: x.title,
authors: x.authors.join(',')
}))
map()
:新資料筆數與原筆數相同,因此使用map()
join()
:回傳仍是 Object,因此使用 arrow function 回傳 Object,authors
Array 使用Array.prototype.join(',')
轉成 String
Point-free
import { pipe, map, lensProp, over, join, pluck } from 'ramda'
let data = [
{
title: 'FP in JavaScript',
authors: [
{ name: 'John'},
{ name: 'Kevin'},
{ name: 'Tom'}
] },
{
title: 'RxJS in Action',
authors: [
{ name: 'Sam' },
{ name: 'Jerry' },
{ name: 'Ray' }
]
},
{
title: 'Speaking JavaScript',
authors: [
{ name: 'May'},
{ name: 'Mary'},
{ name: 'Jen'}
]
}
]
pipe(
map(over(lensProp('authors'), pluck('name'))),
map(over(lensProp('authors'), join(',')))
)(data) // ?
30 行
map(over(lensProp('authors'), pluck('name')))
pluck('name')
:先從 Object Array 取出name
寫入authors
property 使之成單純 Array
亦可使用
map(prop('name'))
,但pluck('name')
較精簡
31 行
map(over(lensProp('authors'), join(',')))
整個關鍵在於 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。
Conclusion
- Ramda 有時很難一步完成,會先使用
map()
達成階段性任務之後,再使用另外一個map()
完成