lodash自分用メモ Collection

lodashは見ておこうと思い立ち、サイトの日本語メモを作成しました。

↓ lodashのES6で書くとこうなるというのはこちらのサイト

You Might Not Need Lodash

https://youmightnotneed.com/lodash/


### `_.countBy(collection, [iteratee=_.identity])`

配列から、[iteratee=_.identity]で渡した条件の結果をkey、条件に当てはまる値の数をvalueに返す。

> 公式）Creates an object composed of keys generated from the results of running each element of collection thru iteratee. The corresponding value of each key is the number of times the key was returned by iteratee. The iteratee is invoked with one argument: (value).

```javascript
let array = [
  { username: 'John', score: 36 },
  { username: 'Jake', score: 50 },
  { username: 'Bill', score: 20 }
]

let object = _.countBy(array, function(rec) {
  return rec.score >= 50
})

// 条件の結果がfalseだったのが２つ、trueが１つ
object // {"false":2,"true":1}
console.log(object.false); // 2
console.log(object.true); // 1
```

各要素の文字列の長さを素早く取得したい

```javascript
_.countBy(['foo', 'man', 'chew','happy','bar'], 'length')
// {"3":3,"4":1,"5":1}
```


### `_.every(collection, [predicate=_.identity])`

全ての値が評価条件をクリアした場合のみtureを返し、一つでも合致していないとfalseを返す。

> 公式）Checks if predicate returns truthy for all elements of collection. Iteration is stopped once predicate returns falsey. The predicate is invoked with three arguments: (value, index|key, collection).

```javascript
let array = [
  { username: 'John', score: 36 },
  { username: 'Jake', score: 50 },
  { username: 'Bill', score: 20 }
]

_.every(array, function(item) {
  return item.score > 0
})
// true

_.every(array, function(item) {
  return item.score > 20
})
// false
```

### `_.filter(collection, [predicate=_.identity])`

配列から条件に合致する値を配列で返す。

> 公式）Iterates over elements of collection, returning an array of all elements predicate returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection).

```javascript
let events = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 === 0 })
events // [2,4,6]
```

```javascript
let array = [
  { username: 'John', score: 36, active: true },
  { username: 'Jake', score: 50, active: true },
  { username: 'Bill', score: 20, active: false }
]

_.filter(array, 'active')
// [{"username":"John","score":36,"active":true},{"username":"Jake","score":50,"active":true}]

_.filter(array, { score: 20 })
// [{"username":"Bill","score":20,"active":false}]
```

### `_.find(collection, [predicate=_.identity], [fromIndex=0])`

ES6の`find`と同じ。要素から条件に合致する、最初の値を返す。

> 公式）Iterates over elements of collection, returning the first element predicate returns truthy for. The predicate is invoked with three arguments: (value, index|key, collection).

```javascript
let array = [
  { username: 'John', score: 36, active: true },
  { username: 'Jake', score: 50, active: true },
  { username: 'Bill', score: 20, active: false }
]

_.find(array, function(item) {
  return item.score > 20
})
// {"username":"John","score":36,"active":true}

_.find(array, ['active', true])
// {"username":"John","score":36,"active":true}
```


### `_.findLast(collection, [predicate=_.identity], [fromIndex=collection.length-1])`

使い方は`_.find`と同じ。要素の右から探して最初に合致する値を返す。

> 公式）This method is like _.find except that it iterates over elements of collection from right to left.

```javascript
let array = [
  { username: 'John', score: 36, active: true },
  { username: 'Jake', score: 50, active: true },
  { username: 'Bill', score: 20, active: false }
]

_.findLast(array, ['active', true])
// {"username":"Jake","score":50,"active":true}
```

### `_.flatMap(collection, [iteratee=_.identity])`

配列の要素に渡した関数を適用した後の結果を展開し、最終結果は連結してフラットになって返ってくる。

> 公式）Creates a flattened array of values by running each element in collection thru iteratee and flattening the mapped results. The iteratee is invoked with three arguments: (value, index|key, collection).

```javascript
function duplicate(n) {
  return [n, n]
}
_.flatMap([1, 2], duplicate) // => [1, 1, 2, 2]

const map = value => [value + 1, value -1]
_.flatMap([1, 2, 3], map) // => [2,0,3,1,4,2]
```

### `_.flatMapDeep(collection, [iteratee=_.identity])`

`_.flatMap`と使い方は一緒だが、返ってくる値は完全に階層を持たない、フラットな配列になる。

> 公式）This method is like _.flatMap except that it recursively flattens the mapped results.

```javascript
const map = value => [[value + 1], [value -1]]
_.flatMap([1, 2, 3], map) // => [[2],[0],[3],[1],[4],[2]]

_.flatMapDeep([1, 2, 3], map) // => [2,0,3,1,4,2]
```


### `_.flatMapDepth(collection, [iteratee=_.identity], [depth=1])`

`_.flatMapDeep`と使い方は似ているが、指定された回数だけ結果がフラットされる点が違う。depthのデフォルト値は1なので、何も指定しなければ`_.flatMap`と同じになる。

> 公式）This method is like _.flatMap except that it recursively flattens the mapped results up to depth times.

```javascript
const duplicate = value => [[[value, value]]];
_.flatMapDepth([1, 2, 3], duplicate, 2)
// [[1,1],[2,2],[3,3]]
```

### `_.forEach(collection, [iteratee=_.identity])`

ES6の`forEach`と同じ。[iteratee=_.identity]で指定した関数をループして処理する。`return false` で `break`。

> 公式）Iterates over elements of collection and invokes iteratee for each element. The iteratee is invoked with three arguments: (value, index|key, collection). Iteratee functions may exit iteration early by explicitly returning false.

```javascript
_.forEach([1, 2], function(value) {
  console.log(value) // `1` → `2` の順に表示
})
```

### `_.forEachRight(collection, [iteratee=_.identity])`

使い方は`_.forEach`と同じだが、配列の右から処理が掛けられて返ってくる。

> 公式）This method is like _.forEach except that it iterates over elements of collection from right to left.

```javascript
_.forEachRight([1, 2], function(value) {
  console.log(value) // `2` → `1` の順に表示
})
```

### `_.groupBy(collection, [iteratee=_.identity])`

配列から、繰り返し実行された処理の結果を、結果をkey、該当する値を配列にして返す。

> 公式）Creates an object composed of keys generated from the results of running each element of collection thru iteratee. The order of grouped values is determined by the order they occur in collection. The corresponding value of each key is an array of elements responsible for generating the key. The iteratee is invoked with one argument: (value).

```javascript
const charaArray = [{
    id: 25,
    name: 'ピカチュウ',
    type: [ 'でんき' ]
},{
    id: 35,
    name: 'ピッピ',
    type: [ 'ノーマル' ]
},{
    id: 39,
    name: 'プリン',
    type: [ 'ノーマル' ]
}]

_.mapKeys(charaArray, 'id')
// {
//   "25": {
//     "id":25,
//     "name":"ピカチュウ",
//     "type":["でんき"]
//   },
//   "35": {
//     "id":35,
//     "name":"ピッピ",
//     "type":["ノーマル"]
//   },
//   "39": {
//     "id":39,
//     "name":"プリン",
//     "type":["ノーマル"]
//   }
// }
```

```javascript
let nums = [2, 20, 4, 3, 7, 8, 32, 42, 256]

const grouped = _.groupBy(nums, function(n){
  return n < 10 ? 'fail' : 'pass'
})

grouped
// {"fail":[2,4,3,7,8],"pass":[20,32,42,256]}
```

```javascript
let clases = [
    {name: '算数', grade: 83},
    {name: '国語', grade: 100},
    {name: '理科', grade: 98}, 
    {name: '社会科', grade: 93},
    {name: '英語', grade: 42},
    {name: '体育', grade: 60}
];

let gradeClases = function (clases) {
  let letters = {
        'A+': 98,
        'A.': 93,
        'A-': 90,
        'B+': 86,
        'B.': 83,
        'B-': 80,
        'C+': 76,
        'C.': 73,
        'C-': 70,
        'D+': 66,
        'D.': 63,
        'D-': 60
    };

  return _.groupBy(clases, function(sub){
    let key = 'F.'

    _.forEach(letters, function(g, letter) {
      if (sub.grade >= g ) {
        key = letter
        return false
      }
    })
    return key
  })
}

gradeClases(clases)
// {
//   "B.":[
//     {"name":"算数","grade":83}
//   ],
//   "A+":[
//     {"name":"国語","grade":100},
//     {"name":"理科","grade":98}
//   ],
//   "A.":[
//     {"name":"社会科","grade":93}
//   ],
//   "F.":[
//     {"name":"英語","grade":42}
//   ],
//   "D-":[
//     {"name":"体育","grade":60}
//   ]
// }
```


### `_.includes(collection, value, [fromIndex=0])`

指定した値がコレクション内にあるかチェックし、あればtrue、なければfalseを返す。コレクションが文字列だった場合、引数で渡した文字列に１文字でも合致していればtrueを返す。

> 公式）Checks if value is in collection. If collection is a string, it's checked for a substring of value, otherwise SameValueZero is used for equality comparisons. If fromIndex is negative, it's used as the offset from the end of collection.

```javascript
// 文字列から探す
let str = 'ピカチュウ, イーブイ, ポケモン';
_.includes(str, 'カビゴン') // true
_.includes(str, 'ピカチュウ') // false

// 配列から探す
let array = ['a','b','c'];
_.includes(array,42) // false
_.includes(array,'d') // false
_.includes(array,'c') // true

// オブジェクトから探す
let object = { name: 'レッド', level: 32 }
_.includes(object, 'name') // false
_.includes(object, 'グリーン') // false
_.includes(object, 'レッド') // true
```


### `_.invokeMap(collection, path, [args])`

引数で指定したものを関数として、実行した結果を配列にして返す。追加の引数も指定できる。

> 公式）Invokes the method at path of each element in collection, returning an array of the results of each invoked method. Any additional arguments are provided to each invoked method. If path is a function, it's invoked for, and this bound to, each element in collection.

```javascript
_.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']]

_.invokeMap(['a', 'b', 'c'], 'toUpperCase') // => ["A","B","C"]

_.invokeMap([['a', 'b'], ['c', 'd']], 'join', '') // => ["ab","cd"]

_.invokeMap([{ a: 1}, { a: 2 }], function(toAdd) {
  return this.a + toAdd
}, 3)
// [4,5]
```

### `_.keyBy(collection, [iteratee=_.identity])`

指定した[iteratee=_.identity]（値または関数）を実行して、結果をkeyとしたオブジェクトを生成する。
使い方は`_.groupBy`と似ているが、最後の要素だけ返すところが違う。

> 公式）Creates an object composed of keys generated from the results of running each element of collection thru iteratee. The corresponding value of each key is the last element responsible for generating the key. The iteratee is invoked with one argument: (value).

```javascript
const charaArray = [{
    id: 25,
    name: 'ピカチュウ',
    type: [ 'でんき' ]
},{
    id: 35,
    name: 'ピッピ',
    type: [ 'ノーマル' ]
},{
    id: 39,
    name: 'プリン',
    type: [ 'ノーマル' ]
}]

// 実行結果は`_.groupBy`と変わらない
_.keyBy(charaArray, 'id')
// {
//   "25":{
//     "id":25,
//     "name":"ピカチュウ",
//     "type":["でんき"]
//   },
//   "35":{
//     "id":35,
//     "name":"ピッピ",
//     "type":["ノーマル"]
//   },
//   "39":{
//     "id":39,
//     "name":"プリン",
//     "type":["ノーマル"]
//   }
// }
```

```javascript
_.keyBy([1, 2, 3], n => n > 1)
// => {"false":1,"true":3}
_.groupBy([1, 2, 3], n => n > 1)
// => {"false":[1],"true":[2,3]}


_.keyBy({ a: 10, b: 20, c: 20 }, val => val / 2 )
// => {"5":10,"10":20}
```

### `_.map(collection, [iteratee=_.identity])`

[iteratee=_.identity]で渡した値・関数などを繰り返し実行した結果を返す。

> 公式）Creates an array of values by running each element in collection thru iteratee. The iteratee is invoked with three arguments:
> (value, index|key, collection).
> Many lodash methods are guarded to work as iteratees for methods like ` _.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.

> The guarded methods are:

```text
ary, chunk, curry, curryRight, drop, dropRight, every, fill, invert, parseInt, random, range, rangeRight, repeat, sampleSize, slice, some, sortBy, split, take, takeRight, template, trim, trimEnd, trimStart, and words
```

```javascript
_.map([1, 2, 3], n => n * 2 ) // => [2,4,6]

const users = [
  { name: 'Alex' },
  { name: 'Bob'}
]

_.map(users, 'name') // => ["Alex","Bob"]
_.map(users, { name: 'Alex' }) // => [true,false]
```

### `_.orderBy(collection, [iteratees=[_.identity]], [orders])`

`_.sortBy`と使い方は一緒だが、ソート順を昇順・降順決められるところが違う。引数で`asc`、`desc`を指定してあげる。

> 公式）This method is like _.sortBy except that it allows specifying the sort orders of the iteratees to sort by. If orders is unspecified, all values are sorted in ascending order. Otherwise, specify an order of "desc" for descending or "asc" for ascending sort order of corresponding values.

```javascript
var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 36 },
  { 'user': 'fred',   'age': 40 },
  { 'user': 'barney', 'age': 34 }
];

_.sortBy(users, ['user', 'age']);
// [{"user":"barney","age":34},{"user":"barney","age":36},{"user":"fred","age":40},{"user":"fred","age":48}]
_.orderBy(users, ['user', 'age'], ['asc', 'desc']);
// [{"user":"barney","age":36},{"user":"barney","age":34},{"user":"fred","age":48},{"user":"fred","age":40}]
```

```javascript
let array = [
  { "id":1, "name":"C" },
  { "id":2, "name":"F" },
  { "id":3, "name":"B" },
  { "id":4, "name":"A" },
  { "id":5, "name":"E" },
  { "id":6, "name":"D" }
]
_.orderBy(array, ['name'], ['asc'])
// => [{"id":4,"name":"A"},{"id":3,"name":"B"},{"id":1,"name":"C"},{"id":6,"name":"D"},{"id":5,"name":"E"},{"id":2,"name":"F"}]
```

### `_.partition(collection, [predicate=_.identity])`

渡した条件によって配列を２つのグループに分ける関数。
１つ目の配列にはtrueの値、２つ目はfalseの値を返す。条件に一致するものとしないものに分別された結果が配列に返ってくる。

> 公式）Creates an array of elements split into two groups, the first of which contains elements predicate returns truthy for, the second of which contains elements predicate returns falsey for. The predicate is invoked with one argument: (value).


```javascript
const users = [
  { id: 1, name: 'Alice',   age: 20 },
  { id: 2, name: 'Bob',     age: 15 },
  { id: 3, name: 'Charlie', age: 10 },
];

_.partition( users, user => user.age < 20 )

// [
//   [
//     {"id":2,"name":"Bob","age":15},
//     {"id":3,"name":"Charlie","age":10}
//   ],
//   [
//     {"id":1,"name":"Alice","age":20}
//   ]
// ]
```

### `_.reduce(collection, [iteratee=_.identity], [accumulator])`

配列またはオブジェクトの左から処理を実行していく。その時、累積した値と処理が実行されるため、単一の値に減らして返す。第三引数の[accumulator]の戻り値の形式を自由に選択できるので、[accumulator]には数値やboolean等も使える。
（ES6のreduceと一緒だが、lodashの方が少し堅牢なのだそう。）

> 公式）Reduces collection to a value which is the accumulated result of running each element in collection thru iteratee, where each successive invocation is supplied the return value of the previous. If accumulator is not given, the first element of collection is used as the initial value. The iteratee is invoked with four arguments:
> (accumulator, value, index|key, collection).
> Many lodash methods are guarded to work as iteratees for methods like _.reduce, _.reduceRight, and _.transform.
> The guarded methods are:
> assign, defaults, defaultsDeep, includes, merge, orderBy, and sortBy


```javascript
// 関数が３回呼び出されている
let sum = _.reduce([1, 1, 1, 1], function(acc, cur) {
	return acc + cur
})
sum // 4
```

```javascript
let array = [1, 2, 3, 4]
let sum = _.reduce(array, (acc, n) => {
	return acc + n
})
sum // 10
```

```javascript
let users = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 29 },
  { name: 'Bill', age: 65 },
  { name: 'Emily', age: 17 },
  { name: 'Jack', age: 30 }
]

let reducedUsers = _.reduce(users, function(result, user) {
  if (user.age >= 18 && user.age <= 59) {
    (result[user.age] || (result[user.age] = [])).push(user)
  }
  return result
}, {})

reducedUsers
// {"29":[{"name":"Jane","age":29}],"30":[{"name":"John","age":30},{"name":"Jack","age":30}]}
```

### `_.reduceRight(collection, [iteratee=_.identity], [accumulator])`

`_.reduce`と使い方は同じだが、処理する順番が右から左。

> 公式）his method is like _.reduce except that it iterates over elements of collection from right to left.

```javascript
let array = [[0, 1], [2, 3], [4, 5]]

_.reduceRight(array, function(flattened, other) {
  return flattened.concat(other)
}, [])
// [4, 5, 2, 3, 0, 1]
```

### `_.reject(collection, [predicate=_.identity])`

配列またはオブジェクトから、指定した条件に合致する値以外を返す。`_.filter`と返ってくる値が逆。

> 公式）The opposite of _.filter; this method returns the elements of collection that predicate does not return truthy for.

```javascript
let users = [
  { 'user': 'barney', 'age': 36, 'active': false },
  { 'user': 'fred',   'age': 40, 'active': true }
]

_.reject(users, { 'age': 40, 'active': true })
// [{"user":"barney","age":36,"active":false}]
_.filter(users, { 'age': 40, 'active': true })
// [{"user":"fred","age":40,"active":true}]
```

```javascript
_.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; })
// [1, 3, 5]
```

### `_.sample(collection)`

コレクションからランダムな要素を取得する。

> 公式）Gets a random element from collection.

```javascript
_.sample([1, 2, 3, 4]) // 2（ランダムな数字1つ返ってくる）
```

### `_.sampleSize(collection, [n=1])`

`_.sample`はランダムな値１つだけ返ってくるが、これは取得できる個数を引数で指定できる。

> 公式）Gets n random elements at unique keys from collection up to the size of collection.

```javascript
_.sampleSize([1, 2, 3], 2) // [3, 1] （ランダムな数字２つ）

_.sampleSize([1, 2, 3], 4) // [2, 3, 1]
```

### `_.shuffle(collection)`

渡した配列をシャッフルしてくれる。

> 公式）Creates an array of shuffled values, using a version of the Fisher-Yates shuffle.

```javascript
_.shuffle([1, 2, 3, 4]) // [4, 1, 3, 2]
```

```javascript
let users = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 29 },
  { name: 'Bill', age: 65 },
  { name: 'Emily', age: 17 },
  { name: 'Jack', age: 30 }
]

users = _.shuffle(users);
// [
//   {"name":"Bill","age":65},
//   {"name":"Jack","age":30},
//   {"name":"Jane","age":29},
//   {"name":"Emily","age":17},
//   {"name":"John","age":30}
// ]
```

### `_.size(collection)`

値の長さやプロパティの数など、lengthを返してくれる。
配列はlength、Stringは文字数。

> 公式）Gets the size of collection by returning its length for array-like values or the number of own enumerable string keyed properties for objects.

```javascript
_.size([1, 2, 3, 4, 5]) // 5

_.size({ 'one': 1, 'two': 2, 'three': 3 }) // 3

_.size('ピカチュウ') // 5
```

### `_.some(collection, [predicate=_.identity])`

コレクションが渡した条件を一つでも満たしていればtrueを返す。
`_.every`は使い方は`_.some`に近いが、全ての条件を満たさないとtrueを返さない。

> 公式）Checks if predicate returns truthy for any element of collection. Iteration is stopped once predicate returns truthy. The predicate is invoked with three arguments: (value, index|key, collection).

```javascript
_.some([3,2,9,6], elem => (elem % 2) == 1) // true
```

```javascript
let pokemons = [
  { id: 1, name: 'Bulbizarre' },
  { id: 2, name: 'Herbizarre' },
  { id: 3, name: 'Florizarre' }
];
_.some(pokemons, { id: 1 }) // true
_.some(pokemons, { id: 4 }) // false
```

### `_.sortBy(collection, [iteratees=[_.identity]])`

コレクション内の各要素で処理が実行された結果を昇順にソートして返す。

> 公式）Creates an array of elements, sorted in ascending order by the results of running each element in a collection thru each iteratee. This method performs a stable sort, that is, it preserves the original sort order of equal elements. The iteratees are invoked with one argument: (value).

```javascript
let nums = [5, 42, -5, 7, 6, 3, 52, 27, 158, -1];
_.sortBy(nums)
// [ -5, -1, 3, 5, 6, 7, 27, 42, 52, 158 ]
```

```javascript
let users = [
  { name: 'John', age: 30 },
  { name: 'Jane', age: 29 },
  { name: 'Bill', age: 65 },
  { name: 'Emily', age: 17 },
  { name: 'Jack', age: 30 }
]

_.sortBy(users, 'age')
// [
//   {"name":"Emily","age":17},
//   {"name":"Jane","age":29},
//   {"name":"John","age":30},
//   {"name":"Jack","age":30},
//   {"name":"Bill","age":65}
// ]
```

```javascript
let pokemons = [
  { name: 'ピカチュウ', lv: 85 },
  { name: 'カビゴン', lv: 40 },
  { name: 'ポッポ', lv: 20 },
  { name: 'フシギバナ', lv: 10 },
  { name: 'ラッタ', lv: 60 }
]

_.sortBy(pokemons, item => {
  return item.name.length
})
// [
//   {"name":"ポッポ","lv":20},
//   {"name":"ラッタ","lv":60},
//   {"name":"カビゴン","lv":40},
//   {"name":"ピカチュウ","lv":85},
//   {"name":"フシギバナ","lv":10}
// ]
```

やっとlodashのCollectionが終わった…！😭
lodashはまだまだ続くので、多分次は別記事を書いてモチベを上げます。