點燈坊

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

如何取得 Nested Array 內所有 Element ?

Sam Xiao's Avatar 2021-05-25

實務上常常用到 chain(),只是一時看不出來而已,可先用已知 Higher Order Function 拆解,最後再重構成 chain()

Version

Ramda 0.27.1

pipe()

import { pipe, prop, map, pluck } from 'ramda'

let data = {
  books: [
    { title: 'Secrets of the JavaScript Ninja',
      authors: [
        { name: 'John Resig' },
        { name: 'Bear Bibeault' }
      ]
    },
    { title: 'RxJS in Action',
      authors: [
        { name: 'Paul P.Daniels' },
        { name: 'Luis Atencio' }
      ]
    }
  ]
}

pipe(
  prop('books'),
  map(prop('authors')),
  map(pluck('name'))
)(data) // ?

data 為 Nested Array,想將所有書的 author 抓出來,最後只有一層 Array。

[ 'John Resig','Bear Bibeault','Paul P.Daniels','Luis Atencio' ]

20 行

pipe(
  prop('books'),
  map(prop('authors')),
  map(pluck('name'))
)(data) // ?

由於是多層 Array,直覺會先用 prop('books') 抓到資料,再使用兩次 map()

但結果是兩層 Array,跟我們預期的一層不同。

unnest000

flatten()

import { pipe, prop, map, pluck, flatten } from 'ramda'

let data = {
  books: [
    { title: 'Secrets of the JavaScript Ninja',
      authors: [
        { name: 'John Resig' },
        { name: 'Bear Bibeault' }
      ]
    },
    { title: 'RxJS in Action',
      authors: [
        { name: 'Paul P.Daniels' },
        { name: 'Luis Atencio' }
      ]
    }
  ]
}

pipe(
  prop('books'),
  map(prop('authors')),
  flatten,
  pluck('name')
)(data) // ?

可先使用 flatten() 攤平一層 Array,再使用 pluck(),如此最後只剩下一層 Array,這正是我們要的結果。

unnest003

chain()

import { pipe, prop, pluck, chain } from 'ramda'

let data = {
  books: [
    { title: 'Secrets of the JavaScript Ninja',
      authors: [
        { name: 'John Resig' },
        { name: 'Bear Bibeault' }
      ]
    },
    { title: 'RxJS in Action',
      authors: [
        { name: 'Paul P.Daniels' },
        { name: 'Luis Atencio' }
      ]
    }
  ]
}

pipe(
  prop('books'),
  chain(prop('authors')),
  pluck('name')
)(data) // ?

pipe(map, flatten) 相當於 chain(),因此可用 chain() 加以化簡。

chain()
(a → b) → [a] → [b]
相當於 flatten()map() 組合

(a -> b):相當於 map function

[a]:data 為 Array

[b]:回傳攤平後的 Array

unnest002

Conclusion

  • 只要是多層 Array,使用 chain() 的機會就很高,若一時看不出來,可先使用 map(),發現多了一層,再使用 flatten() 攤平,當看到 pipe(map, flatten) 時,就會聯想到使用 chain() 重構

Reference

Ramda, chain()