配列で使えるメソッドの復習

# はじめに

Rubyの勉強を始めて早3ヶ月。
これだけはRubyを使う上で覚えておけ、という配列関連のメソッドを教えていただいたので、簡単にまとめてみました。
イメージしやすいよう、下記のようなテーブルとレコードを使います。

| ID | name | price | description |
|:---:|:---:|:---:|:---:|
| 1 | Rubyの本 | 1000 | Rubyの本です。 |
| 2 | JavaScriptの本 | 1000 | JavaScriptの本です。 |
| 3 | PHPの本 | 1000 | PHPの本です。 |
| 4 | HTMLの本 | 2000 | HTMLの本です。 |
| 5 | CSSの本 | 2000 | CSSの本です。 |

# Enumerable#map (collect)

要素の数だけ繰り返しブロックを実行する。
`collect`は`map`の別名で、同様の動きをする。

```rb
items = Item.all
item_ids = items.map { |item| item.id }
# => [1, 2, 3, 4, 5]
```
上記のように各要素に対してメソッドを適用する場合は`&`を使って以下のようにも書くことができる。

```rb
item_ids = items.map(&:id)
```

# Enumerable#select

ブロックを各要素に対し実行し、真となった要素を返す。

```rb
item_price_array = Item.all.map(&:price)
# => [1000, 1000, 1000, 2000, 2000]
only_price_1000 = item_price_array.select { |price| price == 1000 }
# => [1000, 1000, 1000]
```
上記では、`map`を使用して1回値段のみの配列にしてしまったが、下記のようにすれば`price = 1000`だけ配列で取得できる。
（ちょっと例が悪かったため、`where`で解決できてしまいますが。）

```rb
only_price_1000_items = Item.all.select { |item| item.price == 1000 }
# => [#<Item id: 1, name: "Rubyの本", price: 1000, description: "Rubyの本です。", created_at: "2016-10-02 05:32:52", updated_at: "2016-10-02 05:32:52">, #<Item id: 2, name: "JavaScriptの本", pricdescription: "JavaScriptの本です。", created_at: "2016-10-02 07:42:16", updated_at: "2016-10-02 07:42:16">, #<Item id: 3, name: "PHPの本", price: 1000, description: "PHPの本です。", created_at: 09:24:55", updated_at: "2016-10-02 09:24:55">]
```
なお、`select`とは逆で、偽を返す場合は`reject`を使用する。

```rb
not_price_1000_items = Item.all.reject { |item| item.price == 1000 }
# => [#<Item id: 4, name: "HTMLの本", price: 2000, description: "HTMLの本です。", created_at: "2016-10-02 09:25:12", updated_at: "2016-10-02 09:25:12">, #<Item id: 5, name: "CSSの本", price: 2000tion: "CSSの本です。", created_at: "2016-10-02 09:25:59", updated_at: "2016-10-02 09:25:59">]
```

# Enumerable#reduce (inject)

`inject`は`reduce`の別名で、同様の動きをする。
畳み込み演算を行うメソッドをし、その結果を返す。

```rb
item_price_array = Item.all.map(&:price)
# => [1000, 1000, 1000, 2000, 2000]
item_price_array.reduce(0) { |result, price|
  result + price
}
# => 7000
```
まず、`reduce(0)`にある`0`は、次に記載するresultの初期値になる。
ブロック内に記載のある`result`(1つ目のブロック引数）はブロックの戻り値が入る。
`price`(2つ目のブロック引数)は配列の各要素になる。

```rb
# 1週目
result = 0 (初期値), price = 1000
# 2週目
result = 1000, price = 1000
# 3週目
result = 2000, price = 1000
# 4週目
result = 3000, price = 2000
# 5週目
result = 5000, price = 2000
# 戻り値
=> 7000
```
なお、簡単な演算であれば下記のようにシンボルで記述することもできる。

```rb
item_price_array.reduce(:+)
=> 7000
```
初期値に配列を渡すこともできて、フィボナッチ数列などは下記のように書ける。
（引用：[ちょっとわかりにくいけど非常に便利なinjectメソッド](http://akisute3.hatenablog.com/entry/20111122/1322153061)）

```rb
(0..5).reduce([1, 1]) { |fib, i| fib << fib[i] + fib[i+1] }
# => [1, 1, 2, 3, 5, 8, 13, 21]
```

# Enumerable#index_by

特定の値をキーとしたハッシュを生成する。

```rb
items_index_by_name = Item.all.index_by { |item| item.name }
# => => {"Rubyの本"=>#<Item id: 1, name: "Rubyの本", price: 1000, description: "Rubyの本です。", created_at: "2016-10-02 05:32:52", updated_at: "2016-10-02 05:32:52">, "JavaScriptの本"=>#<Item id: 2vaScriptの本", price: 1000, description: "JavaScriptの本です。", created_at: "2016-10-02 07:42:16", updated_at: "2016-10-02 07:42:16">, "PHPの本"=>#<Item id: 3, name: "PHPの本", price: 1000, de"PHPの本です。", created_at: "2016-10-02 09:24:55", updated_at: "2016-10-02 09:24:55">, "HTMLの本"=>#<Item id: 4, name: "HTMLの本", price: 2000, description: "HTMLの本です。", created_at: "20162", updated_at: "2016-10-02 09:25:12">, "CSSの本"=>#<Item id: 5, name: "CSSの本", price: 2000, description: "CSSの本です。", created_at: "2016-10-02 09:25:59", updated_at: "2016-10-02 09:25:59"
```

ここでも`&`を使用すると便利。

```rb
items_index_by_name = Item.all.index_by(&:name)
```

# Enumerable#group_by

特定の値をキーとしてグルーピングした、新しいハッシュを生成する。

```rb
items_group_by_price = Item.all.group_by{ |item| item.price }
# => {1000=>[#<Item id: 1, name: "Rubyの本", price: 1000, description: "Rubyの本です。", created_at: "2016-10-02 05:32:52", updated_at: "2016-10-02 05:32:52">, #<Item id: 2, name: "JavaScriptの本 1000, description: "JavaScriptの本です。", created_at: "2016-10-02 07:42:16", updated_at: "2016-10-02 07:42:16">, #<Item id: 3, name: "PHPの本", price: 1000, description: "PHPの本です。", crea6-10-02 09:24:55", updated_at: "2016-10-02 09:24:55">], 
#     2000=>[#<Item id: 4, name: "HTMLの本", price: 2000, description: "HTMLの本です。", created_at: "2016-10-02 09:25:12", updated_at: "2016-1:25:12">, #<Item id: 5, name: "CSSの本", price: 2000, description: "CSSの本です。", created_at: "2016-10-02 09:25:59", updated_at: "2016-10-02 09:25:59">]}
```
ここでも`&`を使用すると便利。

```rb
items_group_by_price = Item.all.group_by(&:price)
```

## Enumerable#partition

`group_by`と似たグルーピングのメソッドで、`partition`がある。
これはブロック内の要素が真か偽かで新しい配列を生成する。

```rb
items_partition_with_price = Item.all.partition {|item| item.price == 1000 }
# => [
#       [#<Item id: 1, name: "Rubyの本", price: 1000, description: "Rubyの本です。", created_at: "2016-10-02 05:32:52", updated_at: "2016-10-02 05:32:52">, #<Item id: 2, name: "JavaScriptの本", pri description: "JavaScriptの本です。", created_at: "2016-10-02 07:42:16", updated_at: "2016-10-02 07:42:16">, #<Item id: 3, name: "PHPの本", price: 1000, description: "PHPの本です。", created_at2 09:24:55", updated_at: "2016-10-02 09:24:55">], 
#       [#<Item id: 4, name: "HTMLの本", price: 2000, description: "HTMLの本です。", created_at: "2016-10-02 09:25:12", updated_at: "2016-10-02 09:25:1Item id: 5, name: "CSSの本", price: 2000, description: "CSSの本です。", created_at: "2016-10-02 09:25:59", updated_at: "2016-10-02 09:25:59">]
#    ]
```

# おわりに

簡単ではありますが、復習としてまとめました。
`map`と`collect`のように、同一の処理なのにメソッド名が異なるのは、`Lisp`と`Smalltalk`の影響のようです。
下記に詳しく記載されております。
[map と collect、reduce と inject ―― 名前の違いに見る発想の違い](http://magazine.rubyist.net/?0038-MapAndCollect)

もし間違ている、もしくは他にもこんな使い方や便利なメソッドがある、といったことがありましたらぜひ教えてください！