LoginSignup
36
25

More than 5 years have passed since last update.

Ramda おすすめ機能ベスト10

Posted at

Ramdaは関数型プログラミングを補助するJavaScriptライブラリだけど、それとは別に便利な関数もたくさん入っている。便利なものをカウントダウン形式に10個紹介するよ。気になる関数があればAPIドキュメント: http://ramdajs.com/docs/ を見てみよう。

#01. path: 安全なプロパティアクセス

Objectを連想記憶/辞書型/ハッシュテーブルとして使う際に、深いところにあるデータを抜き取るのがめんどくさい。

const obj = {
  cache: {
    user: {
      id: 123,
      name: 'alice',
    },
    contents: {
     ...
    },
}

例えば上記の例だと、名前をとってくるのには name = obj.cache.user.name とやればいいんだけど、例えば obj.cache.user というキーが存在しない場合は、例外がスローされちゃう。めんどい。そんな時は R.path の出番。

R.path(['cache','user','name'], obj) // -> 'alice'
R.path(['cache', 'user', 'name'], { cache: {} }) // -> undefined
R.path(['cache', 'user', 'name'], {}) // -> undefined

#02. range: 連続する数値の生成

[1,2,3,4,5] などのように連続するN個の整数からなる配列を作るのが有効な場面がある。range を使うとすぐ作れる。N回なんかの処理をしたい!とか、オフセットを付けたいとか。

// 1+2+3+....10
R.range(1, 11).reduce((a, x) => a + x, 0); // -> 55
// generate url
R.range(1,5).map(i => `/index?page=${i}`) // -> ['/index?page=1','/index?page=2'... ]

関連: 同じものを何個も作りたい、ってときは repeat もあるけど、癖があるので注意。

#03. scan: reduceっぽい何か

reduce は、配列の値を1個ずつ折りたたんで最終的に1つの値にするけど、scanは同じように折りたたむんだけど、途中経過を配列に保持してくれる。reduceのデバッグに使うのもよし、以下の例のように、いい使い道もあるかも。

// calc factorial
R.scan((a, x) => a * x, 1, R.range(1, 6)) // [ 1, 1, 2, 6, 24, 120 ]

#04. clone: ディープコピー

Ramda もディープコピー機能を提供している。普通はLodashとか使うのかもしれないけど、せっかくRamdaをインポートしてるなら使うのもいいかもね。

const obj1 = { a: [1, 2] };
const obj2 = R.clone(obj1)
obj2.a.pop();
obj1.a.length === obj2.a.length // -> false

#05. pipe: 関数をつなげてつなげて

左から右にどんどん関数を適用していくパターン。最初の関数以外は、引数を1つしかとってはいけない。

const getName = obj => obj.name;
const getMsg = name => `hello ${name}`;
const toUpper = str => str.toUpperCase();
const toLoud = str => str.concat('!');

const f = R.pipe(getName, getMsg, toUpper, toLoud);
f({ name: 'alice' });// -> HELLO ALICE!

右から左にどんどん関数を適用するのは compose だけどこっちのほうが直観的に使える。

#06. once: 絶対に2回以上呼ばせない

何回呼んでも、実際には 2回目以降は呼ばないというスゴ技。返り値は1回目のものが使いまわされる。

const greetOnce = R.once(() => { console.log('hello'); });
greetOnce()
greetOnce()
greetOnce()
greetOnce()
// hello is printed only once.

#07. memoizeWith: 関数呼び出し結果の保存

もし作った関数がpureであれば、同じ引数で何回も関数呼び出しをするのは計算リソースの無駄づかい。1回関数呼び出しをしたら返り値を覚えておいて、2回目以降は覚えておいた返り値を渡すようにする。

const echo = (val) => { console.log(`calc ${val}`); return val;}
const ecoEcho = R.memoizeWith(R.identity, echo);
ecoEcho(1);
ecoEcho(1);
ecoEcho(2);
// print two lines only.

第一引数は、キー作成ロジックであり、よくわからなければR.identity(引数をそのままキーにする)にしておけばよい。

#08. allPass: N回filterする

isXXX() というようなチェックを何回もするような時、例えば、配列を何回もfilterするようなときは、allPassを使うとすっきりした見た目になる。すっきりした見た目はエラーがすくなく、コメントの必要すらなくなる

const isNegative = d => d < 0;
const isEven = d => d % 2 === 0;
const isAllIWant = R.allPass([isNegative, isEven]);
R.range(-4, 10).filter(isAllIWant); // -> [ -4, -2 ]

#09. groupBy: 配列要素をグループ化

配列の要素をいくつかのグループに分けたいことがある。素数とそうでない数だとか、スコアによってAクラス〜Dクラスに分けるとか。groupByはそのための自然な手段を提供してくれる

const byTruth = R.groupBy(o => (o ? 'T' : 'F'));
const arr = [1, 0, -1, '', undefined, null, {}, [], 'hello'];
byTruth(arr);
// -> { T: [ 1, -1, {}, [], 'hello' ], F: [ 0, '', undefined, null ] }

#10. flatten: 配列をきれいに

Qiitaで独自実装している人をよくみる。個人的には使ったことがない。

R.flatten( [1, [2,3], [4,5,[6]] ] ) // -> [1,2,3,4,5,6]
36
25
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
25