Ruby 基本文法【配列・フロー制御編】

## はじめに
Ruby 基本文法シリーズ。今回は、配列・フロー制御に関してです。

## 目次
1. [配列](#配列)
2. [ハッシュ ： 連想配列](#ハッシュ--連想配列)
3. [条件分岐](#条件分岐)
4. [繰り返し](#繰り返し)
5. [参考文献](#参考文献)


## 配列
### 配列作成
-
    ```:フォーマット
    変数 = [値,値,値]
    ```
    ```ruby
    def output_array
      languages = ["Ruby", "Go", "PHP"]

      p languages[0] # 「Ruby」 を取り出す
      p languages[3] # nil ： ゼロ値
      p languages
    end

    output_array
    ```
    ```:実行結果
    "Ruby"
    nil
    ["Ruby", "Go", "PHP"]
    ```

### オブジェクトの追加
配列オブジェクトの追加には、```push```メソッドまたは```<<```を使います。

-
    ```:フォーマット
    オブジェクト.push(追加要素)
    オブジェクト << (追加要素)
    ```
    ```ruby
    languages = ["Ruby", "Go", "PHP"]

    p languages.push("Java") # 「Java」 を追加
    p languages << ("Python") # 「Python」 を追加
    ```
    ```:実行結果
    ["Ruby", "Go", "PHP", "Java"]
    ["Ruby", "Go", "PHP", "Java", "Python"]
    ```

### オブジェクト数を取得
配列のオブジェクト数の取得には、```size```, ```length```, ```count```メソッドを使います。

-
    ```:フォーマット
    オブジェクト.size
    オブジェクト.length
    オブジェクト.count
    ```
    ```ruby
    languages = ["Ruby", "Go", "PHP"]

    p languages.size
    p languages.length
    p languages.count
    ```
    ```:実行結果
    3
    3
    3
    ```

### ソート
配列オブジェクトのソートには、```sort```または```sort.reverse```メソッドを使います。

-
    ```:フォーマット
    オブジェクト.sort ： 昇順
    オブジェクト.sort.reverse ： 降順
    ```
    ```ruby
    p languages.sort
    p languages.sort.reverse
    ```
    ```:実行結果
    ["Go", "PHP", "Ruby"]
    ["Ruby", "PHP", "Go"]
    ```

### ループ
配列オブジェクトをループ処理させるには、```each```メソッドを使います。
<b>ブロックパラメータ</b> ： 各オブジェクトを指すパラメータ、名称はなんでもOK！

-
    ```:フォーマット
    オブジェクト.each do |ブロックパラメータ|
       ループ処理
    end
    ```
    ```ruby
    languages.each do |language|
        p language
    end
    ```
    ```:実行結果
    "Ruby"
    "Go"
    "PHP"
    ```

### 空判定
配列が空かどうかを調べるには、```empty?```メソッドを使います。
空なら true 、空でないなら false を返します。

-
    ```:フォーマット
    オブジェクト.empty?
    ```
    ```ruby
    empty_array = []
    p languages.empty?
    p empty_array.empty?
    ```
    ```:実行結果
    false # 空でない
    true # 空である
    ```

### オブジェクト存在チェック
オブジェクトが配列にあるかどうかを確認するには、```include?```メソッドを使います。
含まれているなら true 、含まれていなければ false を返します。

-
    ```:フォーマット
    オブジェクト.include?(チェック対象)
    ```
    ```ruby
    p languages.include?("Go")
    p languages.include?("C#")
    ```
    ```:実行結果
    true # 含まれている
    false # 含まれていない
    ```

### 条件クリアチェック
配列の全オブジェクトが条件を満たすかどうかを調べるには、```all?```メソッドを使います。
<b>各オブジェクト名</b>に決まりはないです。ブロックパラメータ同様、なんでもOK！

-
    ```:フォーマット
    オブジェクト.all?{|各オブジェクト名| 各オブジェクト名 > 5}
    ```
    ```ruby
    numbers = [1, 5, 18]
    p numbers.all?{|number| number > 0} # number が0以上ならクリア
    p numbers.all?{|number| number > 5} # number が5以上ならクリア
    ```
    ```:実行結果
    true # 全オブジェクトが条件クリア
    false # 一部のオブジェクトが条件クリアできていない
    ```

### 条件クリア(最低１つ)判定
配列内で最低１つ条件を満たすオブジェクトがあるかどうかを調べるには、```any?```メソッドを使います。

-
    ```:フォーマット
    オブジェクト.any?{|各オブジェクト名| 各オブジェクト名 > 5}
    ```
    ```ruby
    numbers = [1, 5, 18]
    p numbers.any?{|number| number > 5} # 5以上ならクリア
    p numbers.any?{|number| number > 20} # 20以上ならクリア
    ```
    ```:実行結果
    true # いずれかのオブジェクトが条件クリア
    false # 全てのオブジェクトが条件クリアできていない
    ```

### 配列の再構築
ある配列をもとに新しい配列を作るには、```map```メソッドを使います。
まだあまり実感はないですが、<b>頻繁に使われるメソッド</b>のようです。

今回は、オブジェクト値を大文字化する処理を行います。

-
    ```:フォーマット
    新しく作成する配列名 = 作成元の配列名.map{
      |各オブジェクト名| 各オブジェクト名.upcase # upcase は例です
    }
    ```
    ```ruby
    countries = ["japan", "canada", "italy"]
    new_countries = countries.map{
      |country| country.upcase
    }
    p new_countries
    ```
    ```:実行結果
    ["JAPAN", "CANADA", "ITALY"]
    ```

## ハッシュ ： 連想配列
次は連想配列についてです。作成方法は全部で3種類あります。

### 連想配列作成
- 
    ```:フォーマット
    ① 変数 = {キー:値, キー:値,,,}
    ② 変数 = {:キー => 値, :キー => 値,,,}
    ③ 変数 = {"キー" => 値, "キー" => 値,,,}
    ```
    ```ruby
    ages1 = {yamaguchi:10, sato:20, matsumoto:30}
    ages2 = {:yamaguchi =>10, :sato=>20, :matsumoto=>30}
    ages3 = {"yamaguchi" => 10, "sato"=>20, "matsumoto"=>30}
    p ages1
    p ages2
    p ages3

    p ages1[:matsumoto] # 変数[:キー名]
    ```
    ```:実行結果
    {:yamaguchi=>10, :sato=>20, :matsumoto=>30}
    {:yamaguchi=>10, :sato=>20, :matsumoto=>30}
    {"yamaguchi"=>10, "sato"=>20, "matsumoto"=>30}
    30
    ```

### オブジェクトの追加
- 
    ```:フォーマット
    変数[:キー名] = 値
    ```
    ```ruby
    ages = {yamaguchi:10, sato:20, matsumoto:30}
    ages[:yamada] = 50
    p ages
    ```
    ```:実行結果
    {:yamaguchi=>10, :sato=>20, :matsumoto=>30, :yamada=>50}
    ```

### オブジェクトの削除
オブジェクトの削除には、```delete```メソッドを使います。

- 
    ```:フォーマット
    変数.delete(:キー名)
    ```
    ```ruby
    ages = {yamaguchi:10, sato:20, matsumoto:30}
    ages.delete(:matsumoto)
    p ages
    ```
    ```:実行結果
    {:yamaguchi=>10, :sato=>20, :yamada=>50}
    ```

## 条件分岐
条件分岐には、以下構文を使います。
- [```if〜else```](#ifelse)
- [```if 修飾子```](#if-修飾子)
- [```unless```](#unless)
- [```unless 修飾子```](#unless-修飾子)
- [```case〜when```](#casewhen)

### if〜else
条件を満たす場合、```if```または```elsif```内の処理を実行します。
いずれの条件を満たしていない場合は、```else```の処理を実行します。

- 
    ```:フォーマット
    if 条件 then
      処理
    elsif 条件 then
      処理
    else
      処理
    end
    ```
    ```ruby
    def output_if
      age = 13
      if age >= 12 then # age が12以上である場合
        print "adult fee\n"
      else # age が12未満である場合
        print "child fee\n"
      end
    end

    output_if
    ```
    ```:実行結果
    adult fee
    ```

### if 修飾子
右辺の条件を満たしている場合にのみ、左辺の処理を行います。
条件を満たしていない場合は、```nil```として何も出力されません。

- 
    ```:フォーマット
    処理 if 条件
    ```
    ```ruby
    age = 13
    puts("num = " + age.to_s) if age >= 12
    puts("num = " + age.to_s) if age <= 12
    ```
    ```:実行結果
    num = 13
    # nil 条件を満たしていないため、出力なし
    ```

### unless
```unless```は```if〜else```と逆の動作をします。
条件を満たしていない場合```unless```内、満たす場合```else```内の処理を実行します。
<b>※```elsif```を指定することはできません。</b>

- 
    ```:フォーマット
    unless 条件
      処理
    else
      処理
    end
    ```
    ```ruby
    age = 13
    unless age >= 12
      print "adult fee\n"
    else
      print "child fee\n"
    end
    ```
    ```:実行結果
    child fee # 条件を満たすため、else以下を出力
    ```

### unless 修飾子
```unless```修飾子は、```if```修飾子と逆の動作をします。
右辺の条件を満たしている場合は、```nil```として何も出力されません。
条件を満たしていない場合にのみ、左辺の処理を行います。

- 
    ```:フォーマット
    処理 unless 条件
    ```
    ```ruby
    age = 13
    puts("num = " + age.to_s) unless age >= 12 # ①
    puts("num = " + age.to_s) unless age <= 12 # ②
    ```
    ```:実行結果
    child fee # ② に対する結果
    ```

### case〜when
```case```の条件と```when```の条件を比較、一致判定を行います。
```case```を満たすいずれかの```when```の処理を実行します。

- 
    ```:フォーマット
    case 条件
    when 条件 ... 条件
      処理
    when 条件 ... 条件
      処理
    else
      処理
    end
    ```
    ```ruby
    age = 13
    case age
    when 0 .. 2
      puts "baby"
    when 3 .. 6
      puts"little child"
    when 7 .. 12
      puts  "child"
    when 13 .. 18
      puts "youth"
    else
      puts "adult"
    end
    ```
    ```:実行結果
    youth # age が13〜18という条件を満たすため
    ```
    ```case```の条件を省略した場合、最初に条件を満たした```when```の処理を実行します。
    いずれの条件も成り立たなければ```nil```を返します。
    ```ruby
    case
    when 0 .. 2 
      puts "baby"
    when 3 .. 6 
      puts"little child"
    when 7 .. 12 
      puts  "child"
    when 13 .. 18
      puts "youth"
    else
      puts "adult"
    end
    ```
    ```:実行結果
    baby
    ```

## 繰り返し
繰り返し(ループ処理)には、以下構文を使います。
- [```while```](#while)
- [```while 修飾子```](#while-修飾子)
- [```until```](#until)
- [```until 修飾子```](#until-修飾子)
- [```for```](#for)
- [```break```](#break)
- [```next```](#next)
- [```redo```](#redo)
- [```retry```](#retry)

### while
条件を満たす場合、```while```内の処理を繰り返し実行します。
条件を満たしていない場合は、```nil```を返します。

- 
    ```:フォーマット
    while 条件 [do]
       処理
    end
    ```
    ```ruby
    def output_where
      numbers = [1,3,5,7,9]
      number = 0
      while number < numbers.length
        p numbers[number]
        number += 1
      end
    end

    output_where
    ```
    ```:実行結果
    1
    3
    5
    7
    9
    ```

### while 修飾子
右辺の条件を満たす場合、左辺の処理を繰り返し実行します。

- 
    ```:フォーマット
    処理 while 条件
    ```
    ```ruby
    str = "Ruby"
    puts "Go" while str == "Ruby"
    ```
   <b>※ 実行結果は無限ループになる(条件を満たし続ける)ため割愛</b>

### until
条件を満たすまで、```until```内の処理を繰り返し実行します。
条件を満たしていない場合は、```nil```を返します。

- 
    ```:フォーマット
    until 条件 [do]
       処理
    end
    ```
    ```ruby
    num = 1
    until num == 5 do
      p num
      num += 1
    end
    ```
    ```:実行結果
    1
    2
    3
    4
    ```

### until 修飾子
右辺の条件を満たすまで、左辺の処理を繰り返し実行します。

- 
    ```:フォーマット
    処理 until 条件
    ```
    ```ruby
    p num until num != 5
    ```
   <b>※ 実行結果は(条件を満たした後)無限ループになるため割愛</b>


### for
オブジェクトの数だけ```for```内の処理を繰り返し実行します。
条件を満たしていないまたは指定オブジェクトがない場合は、```nil```を返します。
各オブジェクトを指す変数名はなんでもOK！

- 
    ```:フォーマット
    for 変数 ...  in オブジェクト [do]
      処理
    end
    ```
    ```ruby
    for i in [1, 2, 3]
      print i*2, "\n"
    end
    ```
    ```:実行結果
    2
    4
    6
    ```
    連想配列の場合は以下のような記述になります。
    ```ruby
    for i,j in [[1,2], [3,4], [5,6]]
      p [i,j]
    end
    ```
    ```:実行結果
    [1, 2]
    [3, 4]
    [5, 6]
    ```

### break
ループを強制的に抜けるには、```break```を使用します。

- 
    ```:フォーマット
    break
    ```
    ```ruby
    i = 0
    while i < 3
      print i, "\n"
      i += 1
      if i == 2  # i が　2　に達したらループを抜ける
        break
      end
    end
    ```
    ```:実行結果
    0
    1
    ```

### next
ループ処理をスキップ(次のループへジャンプ)には、```next```を使用します。

- 
    ```:フォーマット
    next
    ```
    ```ruby
    i = 0
    while i < 3
      i += 1
      if i == 1 # i が 1 の場合、ループ処理をスキップ
        next
      end
      print i, "\n"
    end
    ```
    ```:実行結果
    2
    3
    ```

### redo
ループ処理のやり直しには、```redo```を使用します。

- 
    ```:フォーマット
    redo
    ```
    ```ruby
    count = 0
    languages = ["PHP", "Go", "Ruby", "JavaScript"]

    languages.each do |language|
      p language

      if language == "Ruby" && count < 3 # 「Ruby」 が4回出力されるまで、ループ処理をやり直す
        count += 1
        redo
      end
    end
    ```

### retry
```retry```は、```rescue```節で```begin```式をはじめから再実行するのに使用します。
```rescue```節以外で```retry```が用いられた場合には、```SyntaxError```が発生します。

- 
    ```:フォーマット
    retry
    ```
詳細は以下
https://qiita.com/nao-United92/items/3427a0bc18b193176d88


## 参考文献
<a href="https://docs.ruby-lang.org/ja/latest/doc/index.html">Ruby 3.2 リファレンスマニュアル</a>
<a href="https://docs.ruby-lang.org/ja/latest/doc/spec=2fcontrol.html">【Ruby】基本コマンド一覧</a>
<a href="https://qiita.com/key-amb/items/668fe2e76c43010192a8">Ruby で例外を捕捉して一定回数 retry するメソッド</a>