【Ruby】inject と each_with_object の違い

# 結論
***`inject`***
- **最後に行われたブロックの実行結果を返す。**
- 要素同士を作用させたいときに使用。
- 要素のたたみ込みを行う。

***`each_with_object`***
- **指定されたオブジェクトを返す。**
- 配列やハッシュで使用。
- 各要素に処理を行なった、新しいオブジェクトを返す。

# 解説

まず、2つのメソッドを使用し、連続する1〜10の数値で配列を作ってみます。

```ruby
# inject
(1..10).inject([]) { |ary, num| ary << num }    # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# each_with_object
(1..10).each_with_object([]) { |num, ary| ary << num }    # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
```

この2つは、どちらも`[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`を返します。

次に、この2つに条件をつけてみます。

条件は**偶数の値のみ**を取得し配列にします。
偶数であることの条件分岐なので、`if`と`even?`を使用します。

```ruby
# inject
(1..10).inject([]) { |ary, num| ary << num if num.even? }    # => NoMethodError (undefined method `<<' for nil:NilClass)

# each_with_object
(1..10).each_with_object([]) { |num, ary| ary << num if num.even? }    # => [2, 4, 6, 8, 10]
```

すると、`inject`の方は`NoMethodError`となってしまいます。

エラー内容は、`nil`には`<<`メソッドが定義されてない。
つまり、`inject`内の変数`ary`が`nil`になってしまっています。

これはそれぞれのメソッドの挙動の違いによるものです。

## inject

[リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/inject.html)を確認してみると、

> 最初に初期値 init と self の最初の要素を引数にブロックを実行します。 2 回目以降のループでは、前のブロックの実行結果と self の次の要素を引数に順次ブロックを実行します。そうして最後の要素まで繰り返し、最後のブロックの実行結果を返します。

とあります。

**`初期値 init`**とは、`inject`の後ろについている`()`内の値、今回は空の配列**`[]`**になります。
**`self`**とは`inject`が作用しているもの、今回は1〜10までの数値**`(1..10)`**になります。

先程の例、

```ruby
(1..10).inject([]) { |ary, num| ary << num }
```

で見てみると、

まず、`ary`に初期値である**`[]`**が、`num`に`(1〜10)`の最初の値**`1`**が入り、ブロック({}内)の`ary << num`が実行されます。

```ruby
# |ary, num|
ary = []
num = 1

ary << num  # => [1]
```

次に、先程の実行結果**`[1]`**が`ary`に入り、`num`には`(1〜10)`の次の値**`2`**が入り、ブロック内の`ary << num`つまり、`[1] << 2`が実行されます。

```ruby
# |ary, num|
ary = [1]
num = 2

ary << num  # => [1, 2]
```

次は、また先程と同じように実行結果**`[1, 2]`**が`ary`に入り、`num`には`(1〜10)`の3番目の値**`3`**が入り、またブロック`ary << num ([1, 2] << 3)`が実行されます。

```ruby
# |ary, num|
ary = [1, 2]
num = 3

ary << num  # => [1, 2, 3]
```

この挙動が`(1〜10)`の`10`まで繰り返され、最後の実行結果が返されます。

```ruby
# |ary, num|
ary = [1, 2, 3, 4, 5, 6, 7, 8, 9]
num = 10

ary << num # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  この実行結果が返る
```
### 繰り返しに実行結果が使用されている。

それぞれのブロック内の変数をそのまま出力してみます。

```ruby
# inject
(1..3).inject([]) { |ary, num| p "#{ary} - #{num}:" }

# "[] - 1:"
# "[] - 1: - 2:"
# "[] - 1: - 2: - 3:"
# "[] - 1: - 2: - 3: - 4:"
# "[] - 1: - 2: - 3: - 4: - 5:"
# => "[] - 1: - 2: - 3: - 4: - 5:"
```

**"<font color='Crimson'>ary</font> - <font color='RoyalBlue'>num</font>:"**
**"<font color='Crimson'>[ ]</font> - <font color='RoyalBlue'>1</font>:"**
**"<font color='Crimson'>[ ] - 1:</font> - <font color='RoyalBlue'>2</font>:"**
**"<font color='Crimson'>[ ] - 1: - 2:</font> - <font color='RoyalBlue'>3</font>:"**
**"<font color='Crimson'>実行結果</font> - <font color='RoyalBlue'>要素</font>:"**

上記を見ると、`{ }`の実行結果が次の`ary`に渡されていることがわかります。

## each_with_object

[リファレンスマニュアル](https://docs.ruby-lang.org/ja/latest/method/Enumerable/i/each_with_object.html)を確認してみると、

> 与えられた任意のオブジェクトと要素をブロックに渡し繰り返し、最初に与えられたオブジェクトを返します。

とあります。

**`与えられた任意のオブジェクト`**とは、`each_with_object`の後ろについている`()`内の値、今回は空の配列**`[]`**になります。

先程の例、

```ruby
(1..10).each_with_object([]) { |num, ary| ary << num }
```

で見てみると、

まず、`num`に`(1..10)`の最初の値**`1`**が、`ary`に配列オブジェクト**`[]`**が入り、ブロック内の`ary << num`を実行。配列オブジェクトは**`[1]`**になります。

```ruby
# |num, ary|
num = 1
ary = []

ary << num

ary  # => [1]
```

次に、`num`に`(1..10)`の次の値**`2`**が、`ary`に配列オブジェクト**`[1]`**が入り、ブロック内の`ary << num`を実行。配列オブジェクトは**`[1, 2]`**になります。

```ruby
# |num, ary|
num = 2
ary = [1]

ary << num

ary  # => [1, 2]
```

次は、また同じように`num`に`(1..10)`の3番目の値**`3`**が、`ary`に配列オブジェクト**`[1, 2]`**が入り、ブロック内の`ary << num`を実行。配列オブジェクトは**`[1, 2, 3]`**になります。

```ruby
# |num, ary|
num = 3
ary = [1, 2]

ary << num

ary  # => [1, 2, 3]
```

この挙動が`(1〜10)`の`10`まで繰り返され、最後のオブジェクトが返されます。

```ruby
# |num, ary|
num = 10
ary = [1, 2, 3, 4, 5, 6, 7, 8, 9]

ary ,<< num

ary  # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  この配列オブジェクトが返る
```

### 繰り返しに`(　)`で与えられたオブジェクトが使用されている。

それぞれのブロック内の変数をそのまま出力してみます。

```ruby
# each_with_object
(1..3).each_with_object([]) { |num, ary| p "#{ary} - #{num}" }

# "[] - 1"
# "[] - 2"
# "[] - 3"
# => []
```

**"<font color='Crimson'>ary</font> - <font color='RoyalBlue'>num</font>:"**
**"<font color='Crimson'>[ ]</font> - <font color='RoyalBlue'>1</font>:"**
**"<font color='Crimson'>[ ]</font> - <font color='RoyalBlue'>2</font>:"**
**"<font color='Crimson'>[ ]</font> - <font color='RoyalBlue'>3</font>:"**
**"<font color='Crimson'>指定されたオブジェクト</font> - <font color='RoyalBlue'>要素</font>:"**

`inject`とは違い、`ary`には与えられたオブジェクトが入ります。
上記では`<<`などで配列に追加をしていないため、そのまま`[ ]`が出力されています。

# 最後に

言い回しや解釈の間違っているところがございましたら、ご教示いただけますと幸です。
ご覧いただき、ありがとうございました。