點燈坊

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

使用 find() 搜尋 Array 中的 Element

Sam Xiao's Avatar 2019-10-25

find() 為 Ramda 常用 Function,常搭配 propEq() equals() 一併使用。

Version

macOS Catalina 10.15
VS Code 1.39.2
Quokka 1.0.258
Ramda 0.26.1

Imperative

let data = [
  { id: 1, title: 'FP in JavaScript'},
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

let find = pred => arr => {
  for(let x of arr)
    if (pred(x)) return x;
};

find(x => x.id === 1)(data); // ?

簡單的需求,想找到 id1 的 object。

Imperative 會使用 for loop 搭配 if 判斷,若 pred()true 就 return object。

find000

Array.prototype.reduce()

let data = [
  { id: 1, title: 'FP in JavaScript'},
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

let find = pred => arr => arr.reduce((a, x) => {
  if (a !== undefined) return a;
  if (pred(x)) return x;
}, undefined);

find(x => x.id === 1)(data); // ?

結果為單一 object,因此也可以使用 reduce() 完成。

因為 find() 找不到會回傳 undefined,故 reduce() 的初始值為 undefined

find005

let data = [
  { id: 1, title: 'FP in JavaScript'},
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

let find = pred => arr => arr.reduce((a, x) => (a !== undefined) ? a : (pred(x) ? x : a))

find(x => x.id === 1)(data); // ?

兩個 if 可使用 ?: 加以化簡。

find006

let data = [
  { id: 1, title: 'FP in JavaScript'},
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

let find = pred => arr => arr.reduce((a, x) => a || (pred(x) ? x : a));

find(x => x.id === 1)(data); // ?

因為 a !=== undefind 時剛好回傳 a 自己,而 a 又是 falsy value,剛好可配合 || 使用。

find007

Array.prototype.find()

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

let find = pred => arr => arr.find(pred);

find(x => x.id === 1)(data); // ?

ECMAScript 的 Array.prototype 有內建 find(),可直接使用。

find001

Ramda

import { find } from 'ramda';

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

find(x => x.id === 1)(data); // ?

Ramda 也提供 find(),可直接使用。

find()
(a → Boolean) → [a] → a | undefined
傳回第一個符合條件的資料

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

[a]:data 為 array

a | undefined:若找到回傳為 a,找不到回傳 undefined

find004

Point-free

import { find, propEq } from 'ramda';

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

find(propEq('id')(1))(data); // ?

find() 的 predicate 也可使用 propEq() 加以 point-free。

find002

Function Composition

import { find, propEq, compose } from 'ramda';

let data = [
  { id: 1, title: 'FP in JavaScript' },
  { id: 2, title: 'RxJS in Action' },
  { id: 3, title: 'Speaking JavaScript' },
];

let fn = compose(find, propEq('id'));

fn(1)(data); // ?

也可使用 compose()find()propEq() 組合成新 function。

find003

Conclusion

  • find() 為 Ramda 常用 function,其 predicate 可搭配 propEq()equals() 產生

Reference

Ramda, find()
Ramda, propEq()
Ramda, equals()