點燈坊

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

使用 partition() 合併 Array 中 filter() 與 reject() 資料

Sam Xiao's Avatar 2019-10-30

filter()reject() 都能各自回傳 符合條件不符合條件 資料,若想同時回傳兩者則要使用 partition()

Version

macOS Catalina 10.15
VS Code 1.39.2
Quokka 1.0.258
Ramda 0.26.1

Imperative

import { includes } from 'ramda';

let data = [
  'FP in JavaScript',
  'RxJS in Action',
  'Speaking JavaScript'
];

let partition = pred => arr => {
  let filtered = [];
  let rejected = [];

  for(let x of arr)
    pred(x) ? filtered.push(x) : rejected.push(x);

  return [filtered, rejected];
};

let fn = v => partition(includes(v));

console.dir(fn('JavaScript')(data));

若想同時回傳包含 JavaScript 與不包含 JavaScript 資料,且在各自 array,我們可建立 partition()

  • 使用 filter() 建立 filtered array

  • 使用 reject() 建立 rejected array

  • 最後使用 []filteredrejected 組合成新 array

partition000

Array.prototype.reduce()

import { includes } from 'ramda';

let data = [
  'FP in JavaScript',
  'RxJS in Action',
  'Speaking JavaScript'
];

let partition = pred => arr => 
  arr.reduce((a, x) => {
    let [filterd, rejeccted] = a;

    pred(x) ? filterd.push(x) : rejeccted.push(x);

    return a;
  }, [[], []]);

let fn = v => partition(includes(v));

console.dir(fn('JavaScript')(data));

回傳為單一 array 且以 for loop 實現,因此也可使用 Array.prototype.reduce() 實現。

let [filterd, rejeccted] = a;

以 ES6 的 array destructuring 拆解成 filtered array 與 rejected array。

pred(x) ? filterd.push(x) : rejeccted.push(x);

pred(x) 判斷,各自對 filtered array 與 rejected array 做 push。

return a;

由於 array destructuring 的 filteredrejected 是 reference,因此 a array 已經包含最新結果,直接回傳即可。

partition001

Functional

import { includes, juxt, filter, reject } from 'ramda';

let data = [
  'FP in JavaScript',
  'RxJS in Action',
  'Speaking JavaScript'
];

let partition = juxt([filter, reject]);

let fn = v => partition(includes(v));

console.dir(fn('JavaScript')(data));

由於 partition() 回傳為 array,且各 element 又各由 filter()reject(),剛好適合使用 juxt() 將兩者組合起來。

partition002

Ramda

import { partition, includes } from 'ramda';

let data = [
  'FP in JavaScript',
  'RxJS in Action',
  'Speaking JavaScript'
];

let fn = v => partition(includes(v));

console.dir(fn('JavaScript')(data));

Ramda 已經提供 partition(),可直接使用。

partition()
Filterable f => (a -> Boolean) -> f a -> [f a, f a]
同時回傳 filter() 與 reject() 資料

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

f a:data 為 Filterable

[f a, f a]:新的 array 同時包含 filter()reject() 結果

partition003

Function Composition

import { partition, includes, compose } from 'ramda';

let data = [
  'FP in JavaScript',
  'RxJS in Action',
  'Speaking JavaScript'
];

let fn = compose(partition, includes);

console.dir(fn('JavaScript')(data));

也可使用 compose()includes()partition() 組合起來使 fn() point-free。

partition004

Conclusion

  • partition() 不只適用於 array,也適用於 object 或有 filter() method 的 object

Reference

MDN, Array.prototype.reduce()
Ramda, partition()
Ramda, filter()
Ramda, reject()
Ramda, juxt()
Ramda, includes()