lodash の forEach/map/reduce 系の関数を紹介

JavaScript を使っているなら [lodash](https://lodash.com/docs/) は大変便利なのですが、関数が多すぎてどれ使ったらいいのか解りづらいのが難点です。

ここではその中でも良く使う、配列ループ系の関数群を整理して紹介します。

forEach 系
========

- 配列/オブジェクトをループして処理する。
- `return false` で `break`。
- [forEach](https://lodash.com/docs/4.17.10#forEach): JS標準の `forEach` と違ってオブジェクトでも使える。 `length` プロパティがあったら配列と判断。[forEachRight](https://lodash.com/docs/4.17.10#forEachRight) は逆順。
- [forIn](https://lodash.com/docs/4.17.10#forIn): オブジェクト専用 forEach 。length の影響受けない。親クラスのプロパティも対象。[forInRight](https://lodash.com/docs/4.17.10#forInRight) は逆順。
- [forOwn](https://lodash.com/docs/4.17.10#forOwn): オブジェクト専用 forEach 。length の影響受けない。親クラスのプロパティは対象外。[forInRight](https://lodash.com/docs/4.17.10#forOwnRight) は逆順。

```js
_.forEach([1, 2], function(value) {
  console.log(value);
});
// => `1` → `2` の順に表示
 
_.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
  console.log(key);
});
// => `a` → `b` の順に表示 (とはいえ順番は保証されない)
```


Map 系
========

- 配列/オブジェクトをループして **要素を減らさずに** 値やキーを変更した新しい配列/オブジェクトを作る。
- [map](https://lodash.com/docs/4.17.10#map): JS標準の `map` と違ってオブジェクトでも使える。 **配列** を返す。

```js:map
_.map({ 'a': 4, 'b': 8 }, n => n * n); // => [16, 64] (順序は保証されない)

// _.propertyのショートハンドが使える
var users = [{user: 'barney'}, {user: 'fred'}];
_.map(users, 'user'); // => ['barney', 'fred']
_.map(users, _.property('user')); // 同じ意味
_.map(users, u => u.user); // 同じ意味
```

- [mapKeys](https://lodash.com/docs/4.17.10#mapKeys): オブジェクトのキーを変更する。**オブジェクト** を返す。
- [mapValues](https://lodash.com/docs/4.17.10#mapValues): オブジェクトの値を変更する。**オブジェクト** を返す。

```js
_.mapKeys({ 'a': 1, 'b': 2 }, (value, key) => key + value); // => { 'a1': 1, 'b2': 2 }
_.mapValues({ 'a': 1, 'b': 2 }, (value, key) => key + value); // => { 'a': 'a1', 'b': 'b2' }

// id をキーにハッシュマップを作るのにも使えます。
_.mapKeys([{id: 1}, {id: 2}], v => v.id); // => { 1: {id: 1}, 2: {id: 2} }
```

- [invokeMap](https://lodash.com/docs/4.17.10#invokeMap): 第2引数で指定したものを関数として実行した結果で差し替える。**配列** を返す。

```js:invokeMap
_.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort'); // => [[1, 5, 7], [1, 2, 3]]
_.invokeMap([123, 456], String.prototype.split, ''); // => [['1', '2', '3'], ['4', '5', '6']]
```



reduce/transform 系
======

- 配列/オブジェクトをループして新しい値（accumulator）を作る。
- [reduce](https://lodash.com/docs/4.17.10#reduce) では `accumulator` を戻り値で返す。なので `accumulator` に数値や boolean も使える。
- [transform](https://lodash.com/docs/4.17.10#transform) では `accumulator` を関数の中で書き換える。なので `accumulator` に使えるのは配列とオブジェクトのみ。戻り値はループを中断したい場合に使う。
- [reduceRight](https://lodash.com/docs/4.17.10#reduceRight) はループが逆順に回る。


```js:合計を作る場合
_.reduce([1, 2], (sum, n) => sum + n, 0); // => 3
```

```js:各要素を二乗した新たな配列を作るが、二乗した値が奇数になったらそれ以降の値は切り捨てる場合
_.transform([2, 3, 4], function(result, n) {
  result.push(n *= n);
  return n % 2 == 0;
}, []);
// => [4, 9]
```

```js:値とキーを逆転させる。逆転後、同一キーの値がありえるので、値は配列にする場合

// reduce で実現
_.reduce({ 'a': 1, 'b': 2, 'c': 1 }, (result, value, key) => {
  (result[value] || (result[value] = [])).push(key);
  return result;
}, {});
// => { '1': ['a', 'c'], '2': ['b'] }
 
// transform で実現
_.transform({ 'a': 1, 'b': 2, 'c': 1 }, (result, value, key) => {
  (result[value] || (result[value] = [])).push(key);
}, {});
// => { '1': ['a', 'c'], '2': ['b'] }

// ちなみにこの要件なら invertBy 使ったほうが簡単
_.invertBy({ 'a': 1, 'b': 2, 'c': 1 })
// => { '1': ['a', 'c'], '2': ['b'] }
```




lodash関連の記事
======

- [lodash の path を使う関数でオブジェクト操作が便利になる](https://qiita.com/waterada/items/8c57f37d3decdbc583fe)
- [lodash の forEach/map/reduce 系の関数を紹介](https://qiita.com/waterada/items/22ef4c618050ea766137)
- [lodash ちょっとマニアックだけど便利な関数](https://qiita.com/waterada/items/63eb186e2150d38bb6ed)
- [lodash の debounce や throttle で簡単に負荷対策](https://qiita.com/waterada/items/986660d31bc107dbd91c)