[Ruby入門] 06. 配列を扱う

&gt;&gt; 連載の目次は [こちら！](http://qiita.com/prgseek/items/237d02be844534063f1d)

### ■とりあえず普通に書く
```ruby
arr1 = [1, 2, 3]
arr2 = [99, "aa", 77]
```

### ■文字列の配列を%記法ですっきり書く
```ruby
arr  = %w(waiwai gayagaya heyhey);
name = 'miro'
arr  = %W(ワイワイ 改行\n含むよ 空白と\ 変数#{name}含むよ);
```
+ 半角空白で区切って、文字列要素をクォーテーションなしで指定できる
+ %w は シングルクォーテーション、%W は ダブルクォーテーション で各要素を囲んでいるのと同じ
+ 囲み記号には、英数字と空白・改行以外の文字が利用できる
+ 半角空白そのものを文字列に含めたいときは、バックスラッシュでエスケープする


### ■要素数の取得
```ruby
puts arr1.length
puts arr2.size    # lengthと同じ
puts arr2.count {|item| item.is_a?(String)} # ある条件を満たす要素の数を取得
```


### ■要素へのアクセス

#### [インデックスでのアクセス]
```ruby
puts arr1[1]
puts arr2.at(2)          # at でも取れる
puts arr1[-1]            # 負のインデックスだと、最後から数える(-1が最後の要素)
puts arr2[-2]            # したがって-2だと、最後から２番めの要素
p arr1[99]               # 範囲外だとnilが返る。
p arr2[1..2]             # 範囲指定で配列として取り出す
arr2[0] = 111            # インデックスを指定して値を代入
arr2[1, 2] = ["bb", 88]  # インデックスと要素数を指定して、複数要素をまとめて代入
arr2[1, 0] = "xx"        # 要素数に0を指定すると、挿入になる
arr2[1, 0] = %w[yy qq]   # このとき複数の要素を挿入できる
```

#### [first | last でのアクセス]
```ruby
arr = %w[aa bb cc]
arr2 = arr.first     # 先頭の要素を取得
arr3 = arr.first(2)  # 先頭のn個の要素を配列で取得
arr4 = arr.last      # 末尾の要素を取得
arr5 = arr.last(2)   # 末尾のn個の要素を配列で取得
```

#### [push | pop | shift | unshift でのアクセス（破壊的）]
```ruby
arr = %w[aa bb cc]
arr.push("dd")        # 末尾に要素を追加
arr.unshift("xx")     # 先頭に要素を追加
poped = arr.pop()     # 末尾の要素を削除し、その要素を返す
shifted = arr.shift() # 先頭の要素を削除し、その要素を返す
```


### ■配列に対する繰り返し処理

ループの詳細については、
http://qiita.com/prgseek/items/4140ea928be40f55c68e
を参照

#### [for 文]
```ruby
for item in arr do
  puts item
end
```

#### [each 文]
```ruby
arr.each do |item|
  puts item
end
```

#### [each_with_index 文]
```ruby
bros = ["長男", "次男", "三男"]
bros.each_with_index do |name, i| 
  puts "#{i+1}. #{name}"
end
```

#### [Enumerator オブジェクトからの with_index ]
```ruby
bros = ["長男", "次男", "三男"]
bros.each.with_index(1) do |name, i| 
  puts "#{i}. #{name}"
end
```
+ eachメソッド で Enumerator オブジェトを生成して、そこから with_index メソッドを呼んでループする。これだと、インデックスの初期値を指定することができる！


### ■配列の要素を検索
```ruby
arr = %w[aa bb cc d11 cc e22]
puts arr.index("cc")                      # 先頭から探して、みつかったindexを返す。見つからなければnilを返す
puts arr.rindex("cc")                     # 末尾から探して、みつかったindexを返す。見つからなければnilを返す
puts arr.include?("d11")                 # ある要素が含まれているか
puts arr.find {|item| item=~/[a-z]\d{2}/} # ある条件に該当する要素を検索し、`最初に見つかった要素`を返す。detectも同じ。
puts arr.all? {|item| item=~/^[a-z]/}     # すべての要素が、ある条件に該当するか
puts arr.any? {|item| item=~/[0-9]$/}     # いれずかの要素が、ある条件に該当するか
p arr.select {|item| item=~/[a-z]\d{2}/}  # ある条件に該当する要素をすべて拾って、配列で返す
```

### ■配列の要素の削除
```ruby
arr = %w[aa bb cc d12 ee f98 gg]
deleted = arr.delete("bb")              # 要素を指定して、該当する要素(==で判定)を全て削除（破壊的）。削除された要素を返す。
deleted = arr.delete_at(1)              # indexを指定して要素を削除（破壊的）。削除された要素を返す
arr.delete_if {|x| x=~/d[0-9]{2}/ }     # ある条件に該当する要素を全て削除（破壊的）
brr = arr.reject {|x| x=~/f[0-9]{2}/ }  # ある条件に該当する要素を全て削除（非破壊的。!を付ければ破壊的）
arr.clear                               # 全要素を削除。空っぽの配列 [] になる（破壊的）
```


### ■配列をソートする
```ruby
arr = [55, 47, 111, 36, 18, 1]
sorted = arr.sort                        # 1
sorted = arr.sort{|a, b| b <=> a }       # 2
sorted = arr.sort_by{|x| -x}             # 3

arr = %w[xyz bbb 0101 あいうえお test]      # 4
arr1 = arr.sort                          # 5
arr2 = arr.sort.reverse                  # 6

arr = [["c", 10], ["a", 20], ["b", 30]]  # 7
arr2 = arr.sort                          # 8
arr3 = arr.sort {|a,b| a[1] <=> b[1] }   # 9
```
1. <=>演算子で判定して小さい順に並べる。数値なら普通に昇順になる。!を付けると破壊的
1. sortメソッドでルールを指定する。上記は逆順の例。ブロックの戻り値によって要素を比較して並べる（戻り値が-1ならaが小さい、0なら同じ、1ならbが大きい）
1. sort_by のほうが高速。上記は逆順の例。ブロックは要素を単独で処理して返し、最後に全体を<=>演算子で判定して小さい順に並べる。!を付けると破壊的
1. 文字列の配列をソートしてみる...
1. 昇順。["0101", "bbb", "test", "xyz", "あいうえお"]
1. 降順。["あいうえお", "xyz", "test", "bbb", "0101"]
1. 多次元配列をソートしてみる...
1. 普通にソートすると、それぞれの一つ目の要素でソートされる。上記例だと ["a", 20], ["b", 30], ["c", 10]]
1. ブロックを使って、それぞれの２つめの要素でソートしてみる。上記例だと [["c", 10], ["a", 20], ["b", 30]]




### ■配列を結合する
```ruby
arr1, arr2 = [1, 2], %w[aa bb]
arr1.concat(arr2)   # [1, 2, "aa", "bb"] 配列の要素の後ろに別の配列の要素を追加。破壊的。
arr3 = arr1 + arr2  # [1, 2, "aa", "bb"] +演算子でも結合できる。こちらは非破壊的。
```


### ■ inject メソッドで配列の要素の合計を得る

#### ●結論をさきに...
```ruby
arr = [3, 4, 5, 6, 7]

# 合計を得る
total = arr.inject(:+)
p total  # 25
```

#### ●inject メソッドを理解する

inject メソッドは、Enumerable モジュールのメソッド。
集合の要素に対して、繰り返し計算を行うためのメソッド。

```ruby
inject {|before_result, item| 処理 }
```

injectにブロックを渡すと、配列の要素を順に巡って、
①要素1と要素2 → ②ブロックの前回の戻り値と要素3 → ③ブロックの前回の戻り値と要素4 ...
のように順に値を渡してくれる（ 上記の、|before_result, item| の部分 ）
なので、そこで好きに処理をして返せば次のブロック実行に値が渡され、結果として全要素を通じた処理ができる。

また、inject の引数として初期値を渡すと、最初に 初期値と要素1 を渡してくれる

```ruby
inject(初期値) {|before_result, item| 処理 }
```

①初期値と要素1 → ②ブロックの前回の戻り値と要素2 → ③ブロックの前回の戻り値と要素3 ...

injectを利用して、配列の要素の合計を得ることができる。

```ruby
arr = [3, 4, 5, 6, 7]

# 合計を得る
total = arr.inject {|before_result, item| before_result + item }
p total  # 25

# 合計を得る（初期値に0を渡す）
total = arr.inject(0) {|before_result, item| before_result + item }
p total  # 25

# 合計の取得に関しては、以下のように簡潔に書ける
total = arr.inject(:+)
p total  # 25
```


### ■Arrayクラスでnewする

あまりやらないかも...

```ruby
arr = Array.new    # []
arr = Array.new(3) # [nil, nil, nil]

arr = Array.new(3, "Ya!") #["Ya!", "Ya!", "Ya!"]
arr[0].concat("!!")       # このとき全部同じオブジェクトなので、値を破壊的に変更すると...
puts arr[1]               # Ya!!! 他の要素も変わる

arr = Array.new(3){"Ya!"} #["Ya!", "Ya!", "Ya!"]
arr[0].concat("!!")       # こちらは同値だが別オブジェクトなので、値を破壊的に変更しても...
puts arr[1]               # Ya! 他の要素の値は変わらない
```


### ■配列の複製
#### ・浅いコピー
```ruby
arr1 = %w[aaa bbb ccc]
arr2 = arr1.dup           # 複製。このとき、それぞれのオブジェクトは同一なので...
arr1[1].upcase!           # 値を破壊的に変更すると...
puts arr2[1]              # BBB もう一方の配列の要素も変更されている
```

#### ・深いコピー（ネストした配列で試してみる）
```ruby
arr1 = [%w[aaa bbb ccc], %w[xxx yyy zzz], %w[ooo ppp qqq]]
arr2 = Marshal.load(Marshal.dump(arr1))    # 要素も複製してくれる
arr1[1][1].upcase!                         # 値を破壊的に変更しても...
puts arr2[1][1]                            # yyy もう一方は影響を受けていない
```

#### ・オブジェクトIDを確認してみる
```ruby
a = %w[aa, bb]; puts a.object_id, a[1].object_id                     # 1 コピー元の配列を用意
b = a;          puts b.object_id, b[1].object_id                     # 2 参照の代入
c = a.dup;      puts c.object_id, c[1].object_id                     # 3 浅いコピー
d = Marshal.load(Marshal.dump(a));  puts d.object_id, d[1].object_id # 4 深いコピー
```
1. aは、70134350252440, 70134350252740
1. bも、70134350252440, 70134350252740 同じ配列を参照していて、要素も同じオブジェクトを参照している
1. cは、70134350251120, 70134350252740 配列自体は別オブジェクトを参照しているが、要素は同じオブジェクトを参照している
1. dは、70134350250840, 70134350250780 配列自体も、要素も別のオブジェクトを参照している


### ■その他のよく使いそうなメソッド

#### ・配列が空かどうか判定する
```ruby
arr1 = [1, 2]; p arr1.empty?  # false
arr2 = []; p arr2.empty?      # true
```

#### ・指定文字区切りで繋いで文字列にする
```ruby
str = %w[aa bb cc].join(',')  # 引数無しだと、べたっとくっつける
```

#### ・最大値/最小値
```ruby
puts arr.max
puts arr.min
```

#### ・重複排除
```ruby
arr = %w[aa bb bb cc aa aa dd]
arr2 = arr.uniq  # !を付けると破壊的
```

#### ・nil の要素を取り除く
```ruby
arr = [1, nil, 2, nil, nil, 3, 4, 5]
arr2 = arr.compact  # !を付けると破壊的
```

#### ・配列の全ての要素を編集する
```ruby
arr = [1, 2, 3, 4, 5]
arr2 = arr.map {|item| item*10}  # collect でも同じ。!を付けると破壊的
```

#### ・要素を逆に並べ替える
```ruby
arr_r = arr.reverse
```

#### ・ランダムに要素を取り出す
```ruby
puts [1, 2, 3, 4, 5].sample  # 値を一つ
p [1, 2, 3, 4, 5].sample(2)  # 値を複数、配列で。
```