Ruby の Array#inject について

Ruby の認定試験を受ける後輩から Array#inject が わかりにくいという話を聞いたので 簡単にまとめてみたいと思います。

Array#inject は配列の値を合計したりするのに使える便利なメソッドです。

$ irb
irb(main):001:0> [1,2,3,4].inject(0) { | sum, i | sum + i }
=> 10

内部的には次のような処理になります。

[1,2,3,4].inject(0) { | sum, i | sum + i }
                  `-------,
        loop: 1           0, 1     0 + 1
                                   ~~|~~
                          ,----------'
        loop: 2           1, 2     1 + 2
                                   ~~|~~
                          ,----------'
        loop: 3           3, 3     3 + 3
                                   ~~|~~
                          ,----------'
        loop: 4           6, 4     6 + 4
                                   ~~|~~
                                     `----> 出力

2つめのブロック引数には配列の値がはいるのですが 1つめのブロック引数には、前回のループの最後の処理結果が入ります。

1巡目 (loop:1) の1つめのブロック引数は、 前回の処理結果がないので、初期値として inject メソッドの引数が設定されます。

ブロック内をわかりやすく書くと次のようになります。

irb(main):001:0> [1,2,3,4].inject(0) { | sum, i | sum += i }
=> 10

ここまでは簡単なのですが、この inject メソッドは 引数を省略することができます。 この場合の動きが要注意です。

上と同じ配列で試してみます。

irb(main):001:0> [1,2,3,4].inject { | sum, i | sum + i }
=> 10

結果は同じでした。

ここで、ブロック内の処理を変えてみます。

irb(main):001:0> [1,2,3,4].inject(0) { | sum, i | sum * i }
=> 0
irb(main):002:0> [1,2,3,4].inject { | sum, i | sum * i }
=> 24

まったく異なる結果になりました。

まず、引数がある場合の内部処理を見てみます。

[1,2,3,4].inject(0) { | sum, i | sum * i }
                  `-------,
        loop: 1           0, 1     0 * 1
                                   ~~|~~
                          ,----------'
        loop: 2           0, 2     0 * 2
                                   ~~|~~
                          ,----------'
        loop: 3           0, 3     0 * 3
                                   ~~|~~
                          ,----------'
        loop: 4           0, 4     0 * 4
                                   ~~|~~
                                     `----> 出力

次に、引数がない場合の内部処理を見てみます。

[1,2,3,4].inject { | sum, i | sum * i }
  `--------------------,
        loop: 1        1, 2     1 * 2
                                ~~|~~
                       ,----------'
        loop: 2        2, 3     2 * 3
                                ~~|~~
                       ,----------'
        loop: 3        6, 4     6 * 4
                                ~~|~~
                                  `----> 出力

このように 初期値として 配列の 1つめの値が入っています。 また、1巡目 (loop:1) で 配列の 2つめの値が入っています。 ループの数も 1つ少なくなります。 引数を省略すると、 配列の 1つめのを値を初期値として利用するわけです。

つまり、次の 2つが等価となります。

irb(main):001:0> [1,2,3,4].inject(0) { | sum, i | sum * i }
=> 0
irb(main):002:0> [0,1,2,3,4].inject { | sum, i | sum * i }
=> 0

Ruby インストーラー Rumix を試してみる

Windows 環境に簡単に Ruby の実行環境を作るフリーソフトが紹介されていたので 試しにインストールしてみました。

Windowsでスクリプト言語“Ruby”を導入するための和製インストーラー「Rumix」

まず、以下のサイトから Rumix をダウンロードします。

Rumix - Ruby Starter Package with Installer

これを書いている時点では「 Rumix 1.00(通常版)」「 Rumix 1.00(ruby 1.9.1版) 」と ありますが、どちらが良いかわからない人は「 Rumix 1.00(通常版)」を落としましょう。

ダウロードしたファイルを解凍して、その中の rumix_install.exe を実行します。

「次へ」ボタンを押します。

WRITE_0197_01

「次へ」ボタンを押します。

WRITE_0197_02

「次へ」ボタンを押します。

WRITE_0197_04

「次へ」ボタンを押します。

WRITE_0197_06

「次へ」ボタンを押します。

WRITE_0197_07

「次へ」ボタンを押します。

WRITE_0197_08

「次へ」ボタンを押します。

WRITE_0197_09

「インストール」ボタンを押します。

WRITE_0197_10

終わるのを待ちます。

WRITE_0197_11

待ちます。

WRITE_0197_12

待ちます。

WRITE_0197_13

これでインストールは終了です。

次に ruby スクリプトを作って実行させてみます。

デスクトップに test.rb というファイルを作って テキストエディタで スクリプトを書きます。

puts 'hello world!'

スタートメニューから
「 NYACUS (コマンドラインシェル) 」を起動します。

WRITE_0197_14

[d:\]
$ 

NYACUS は Linux のシェルの操作ができる便利なツールです。

cd や ls, pwd などのコマンドも使えます。 ウィンドウにドラッグ&ドロップしてパスを指定することもできます。

[d:\]
$ cd d:\desktop
[d:\desktop]
$ pwd
d:\desktop

先ほど書いたスクリプトを実行させてみます。

WRITE_0197_15

"ruby test.rb" でも 直接指定でも実行させることができます。

簡単に ruby のスクリプトを実行できるので Ruby の試験勉強などにも とても役に立ちます。