Ruby技術者認定試験 silver その1(配列)


## はじめに
備忘録として自分の勉強法をまとめておきます。
また，Ruby技術者認定試験を今後受けようと思っている方のお役に立てれば幸いです。

## each
ブロックに繰り返し要素を渡す。

```ruby:each
# すべての要素の和を求める
numbers = [1, 2, 3, 4, 5]
sum = 0
numbers.each { |n| sum += n }
sum #=> 15
```

### delete_if
指定した条件に一致する要素を削除する。

```ruby:delete_if
numbers = [1, 2, 3, 4, 5]
numbers.delete_if { |n| n.even? }
numbers #=> [1, 3, 5]
```

### map
ブロックが返す値からなる配列を作成する。

```ruby:map
# すべて2倍にした配列を返す
numbers = [1, 2, 3, 4, 5]
double_numbers = numbers.map { |n| n * 2 }
double_numbers = [2, 4, 6, 8, 10]
```
> **Note:**
> `map`は`collect`と同義

### select
ブロックが真を返す要素からなる配列を作成する。

```ruby:select
# 奇数を集める
numbers = [1, 2, 3, 4, 5]
odd_numbers = numbers.select { |n| n.odd? }
odd_numbers #=> [1, 3, 5]
```

> **Note:**
> `select`は`find_all`と同義

### reject

ブロックが偽を返す要素からなる配列を作成する。

```ruby:reject
# 2で割れる数を除く
numbers = [1, 2, 3, 4, 5]
odd_numbers = numbers.reject { |n| n % 2 == 0 }
odd_numbers #=> [1, 3, 5]
```

### find

ブロックが真となる最初の要素を返す。

```ruby:find
# 最初の偶数を探す
numbers = [1, 2, 3, 4, 5]
even_number = numbers.find { |n| n.even? }

even_number #=> 2
```

> **Note:**
> `find`は`detect`と同義
> `find`と`detect`は`Enumerable`モジュールのメソッド

### inject

たたみ込み演算をおこなう。

```ruby:indect
# すべての要素の和を求める
numbers = [1, 2, 3, 4, 5]
sum = numbers.inject(0) { |result, n| result + n }

sum #=> 15
```

ブロックの第一引き数は、

* 1回目のみ`inject`の引き数
* 2回目以降は前回のブロックの返り値

ブロックの第二引き数は、配列の各要素が順に入る。

上のコードの処理の流れ

1. result = 0, n = 1 → 0 + 1 = 1
2. result = 1, n = 2 → 1 + 2 = 3
3. result = 3, n = 3 → 3 + 3 = 6
4. result = 6, n = 4 → 7 + 4 = 10
5. result = 10, n = 5 → 10 + 5 = 15

> **Note:**
> `inject`は`reduce`と同義

## 簡潔に書く

メソッドにブロックを渡す代わりに、`&:メソッド名`を引き数として渡す。

```ruby

numbers = [1, 2, 3, 4, 5]

# これを
odd_numbers = numbers.select { |n| n.odd? }

# こう
odd_numbers = numbers.select(&:odd?)
```

次の条件を満たす場合に使うことができる。

### 条件

* ブロック引数が1つだけ
* ブロック内で呼び出すメソッドに引数がない
* ブロック内は、ブロック引数に対してメソッドを１回呼び出す処理のみ

（追記）正確には、、ブロック引き数が２つでも使える場合があります。
以下コメントからの引用

> 「メソッドにブロックを渡す代わりに、&:メソッド名を引き数として渡す。」についてですが，

> ```ruby
a = [1, 2, 3]
a.inject(&:+) # => 6
```
という例もあります。
`inject(&:+)` はほぼ`inject{ |r, x| r.+(x) }`です。
つまり，ブロックパラメーターが二つ以上の場合にもこういう記法が使えます。

## 添字付きの繰り返し

* each\_with\_index
* with_index

### each\_with\_index

ブロックに繰り返し要素と添字を渡す。

```ruby:each_with_index
# i には　0, 1, 2　がはいる
animals = ["dog", "cat", "mouse"]
animals.each_with_index { |animal, i| puts "#{i + 1}. #{animal}" }

#=>
# 1. dog
# 2. cat
# 3. mouse
```

### with_index

`each`以外のメソッドに添え字を付ける場合は、各メソッドと`with_index`メソッドを組み合わせる。

```ruby:map.with_index
# map に添え字を付ける
animals = ["dog", "cat", "mouse"]
animals.map.with_index { |animal, i| "#{i + 1}. #{animal}" }

#=> ["1. dog", "2. cat", "3. mouse"]
```

#### 添字を0以外から始める

`with_index`に引き数を渡す。

```ruby:with_index(1)
# 添字を 1 から始める
animals = ["dog", "cat", "mouse"]
animals.map.with_index(1) { |animal, i| "#{i}. #{animal}" }

#=> ["1. dog", "2. cat", "3. mouse"]
```

## 配列の配列に対する繰り返し

ブロック引き数に配列が渡ってくるときは、ブロック引き数を複数個用意する。

```ruby
dimensions = [
	# [縦, 横]
	[10, 20],
	[30, 40],
	[50, 60],
]

# それぞれの面積を求める
areas = []

# 改良前
dimentions.each { |dimention| areas << dimention[0] * dimention[1] }
# 改良後
dimentions.each { |length, width| areas << length * width }

areas #=> [200, 1200, 3000]
```

### 添字を付ける

`with_index` + ブロック引き数を()で囲む。

```ruby
dimensions = [
	# [縦, 横]
	[10, 20],
	[30, 40],
	[50, 60],
]

dimensions.each.with_index do |(length, width), i|
	puts "#{length}, #{width}, #{i}"
end

#=>
# 10, 20, 0
# 30, 40, 1
# 50, 60, 2
```

### push 

配列を合体する

```ruby:push
array = [1, 2, 3]
array.push(10, 100)
p array
[1, 2, 3, 10, 100]
```
```ruby:push
arr_1 = [0, 1, 2]
=> [0, 1, 2]
arr_2 = [8, 9, 10]
=> [8, 9, 10]
arr_1.push(arr_2))
=> [0, 1, 2, [8, 9, 10]]
```

pushは「<<」と同義

```ruby
a = [1, 2]
=> [1, 2]

b = [3, 4]
=> [3, 4]

a << b
=> [1, 2, [3, 4]]
```

どちらも重複した配列になる。

### concat

配列を合体する

```ruby:concat
arr_1 = [0, 1, 2]
=> [0, 1, 2]

arr_2 = [8, 9, 10]
=> [8, 9, 10]

 arr_1.concat(arr_2)
=> [1, 2, 3, 8, 9, 10]
```

+演算子と同義。

```ruby
a = [1, 2]
=> [1, 2]

b = [3, 4]
=> [3, 4]

a + b
=> [1, 2, 3, 4]
```

重複しない。


### flatten!

：重複配列をフラットにする
(flattenでも可)
「!」は破壊的メソッドなので使用しないほうがいいかも。

```ruby:flatten
arr_1 = [0, 1, 2]
=> [0, 1, 2]

arr_2 = [8, 9, 10]
=> [8, 9, 10]

arr_1.push(arr_2))
=> [0, 1, 2, [8, 9, 10]]
# 重複しても、、、

arr_1.flatten!
=> [0, 1, 2, 8, 9, 10]
# 解決！
```


# 配列の要素を数指定で取得
```ruby:sample
arr = [0,1,2,3,4,5,6,7,8,9,10]
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 「.」が2つのとき、10個の要素
arr[0..9]
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 「.」が2つのとき、10個の要素
arr[1..9]
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]

# 「.」が3つのとき、9個の要素
arr[0...9]
=> [0, 1, 2, 3, 4, 5, 6, 7, 8]

# [0..9]の中からランダムに2つだけ取る
arr[0..9].sample(2)
=> [4, 2]
```

### sample

要素をランダムに取得する

```ruby:sample
arr = [0,1,2,3,4,5,6,7,8,9,10]
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

arr.sample(4)
=> [0, 8, 1, 4]
```

### shuffle

シャッフルする

```rubyshuffle
arr = [0,1,2,3,4,5,6,7,8,9,10]
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

arr.shuffle
=> [4, 8, 9, 2, 5, 1, 3, 7, 10, 0, 6]

arr.shuffle!
=> [5, 0, 4, 7, 6, 2, 1, 9, 10, 3, 8]
```

### uniq

重複した要素を取り除く

```ruby
a = [0, 1, 2, 4, 6, 3]
=> [0, 1, 2, 4, 6, 3]

b = [0, 1, 2, 6, 3, 5]
=> [0, 1, 2, 6, 3, 5]

c = ((a.sample(3)) + (b.sample(3)))
=> [6, 2, 1, 2, 5, 6]

# ユニークにする
c = ((a.sample(3)) + (b.sample(3))).shuffle!.uniq
=> [0, 6, 2, 3]

c = ((a.sample(3).uniq) + (b.sample(3)).uniq).shuffle!
=> [3, 1, 1, 2, 0, 4]

c = ((a.sample(3)) + (b.sample(3))).uniq.shuffle!
=> [4, 2, 3, 1, 6]

c = ((a.sample(3)) + (b.sample(3))).uniq.shuffle!
=> [0, 6, 4, 3, 1, 2]
```

### combination

組み合わせ

```ruby
arr = [1, 2, 3]
=> [1, 2, 3]

arr.combination(2){|x| print x}
[1, 2][1, 3][2, 3]=> [1, 2, 3]
```

3個の要素から2個を選んだ。
3C2の計算 = 3P2/2! = 3通り

### permutation

順列

```ruby
arr = [1, 2, 3]
=> [1, 2, 3]

arr.permutation(2){|x| print x}
[1, 2][1, 3][2, 1][2, 3][3, 1][3, 2]=> [1, 2, 3]
```

3P2 = 6通り