點燈坊

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

使用 none() 判斷 Array 中資料是否全部不符合條件

Sam Xiao's Avatar 2020-01-24

實務上我們常需判斷 Array 是否 全部不 符合某條件,若都不存在則傳回 true,否則傳回 false

Version

macOS Catalina 10.15
VS Code 1.39.2
Quokka 1.0.256
ECMAScript 2015
Ramda 0.26.1

Imperative

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let none = fn => arr => {
  for (let x of arr) {
    if (fn(x)) return false
  }
  return true
}

none(x => x.price === 400)(data) // ?

建立 none(),Imperative 會使用 for loop 搭配 if 判斷,若符合條件就直接回傳 false,若都不符合條件則回傳 true

none000

reduce()

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let none = fn => arr => arr.reduce((a, v) => a && !fn(v), true)

none(x => x.price === 400)(data) // ?

由於結果為單一 boolean,因次特別適合使用 reduce() 產生。

none004

Functional

import { compose, any, complement } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let none = compose(complement, any)

none(x => x.price === 400)(data) // ?

其實仔細想一想,none() 不就是 not any() 嗎 ? 因此我們也可以將 complement()any() 組合產生 none()

none001

Ramda

import { none } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

none(x => x.price === 400)(data) // ?

Ramda 已經內建 none(),可直接使用。

none()
(a -> Boolean) -> [a] -> Boolean
判斷 array 中資料是否全部不符合條件

(a -> Boolean): 判斷條件 predicate

[a]:data 為 array

Boolean:回傳比較結果

none003

Point-free

import { none, propEq } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

none(propEq('price')(400))(data) // ?

none() 的 callback 也可改用 propEq() 產生,語意更佳。

none002

Function Composition

import { none, propEq, compose } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 }
]

let fn = compose(none, propEq('price'))

fn(400)(data) // ?

亦可使用 compose()propEq()none() 組合起來。

none005

Conclusion

  • ECMAScript 並沒有內建 none()
  • 由於結果為單一 boolean,因此適合使用 reduce() 產生
  • none() 也可以使用 any() 組合出來,再次見證 function composition 威力
  • none() 的 callback 也可用 Ramda 的 function 產生,point-free 更精簡,且可讀性更高
  • 當 callback 也 point-free 後,就更能看出 function composition 雛形,可使用 compose()none() 與 callback 組合起來

Reference

MDN, Array.prototype.reduce()
Ramda, none()
Ramda, any()
Ramda, complement()