【Ruby】Pythonistaの自分がRubyのPythonにはない機能をまとめていく

# 【Ruby】Pythonistaの自分がRubyのPythonにはない機能をまとめてみた

 Rubyを新しく学習するにあたって、RubyのPythonにはない(知らないだけであるのかもしれないけど)機能や、新しく知ったことのみを随時まとめていきます。



## 真偽値と条件分岐

### 真偽値ルール

- `false`または`nil`であれば偽
- それ以外は全部真。

```ruby
# !!を前につけることでbool値に変換する
!!true  #=> true
!!1  #=> true
!!0  #=> true
!!-1  #=> true
!!'true'  #=> true
!!'false'  #=> true
!!''  #=> true
!![]  #=> true
```

真偽値ルールがpythonと違うのは結構厄介な気がする、こんがらがりそう。



#### 空判定

```ruby
''.empty?  #=> true
[].empty?  #=> true
'abc'.empty?  #=> false
[1, 2, 3].empty?  #=> false
```



#### 0判定

```ruby
0.zero?  #=> true
1.zero?  #=> false
```



#### 文字列が含まれているか判定

```ruby
'soccer'.include?('ce')  #=> true
'soccer'.include?('at')  #=> false
```



#### 奇数判定

```ruby
1.odd?  #=> true
2.odd?  #=> false
```



#### nil判定

```ruby
nil.nil?  #=> true
'abc'.nil?  #=> false
```



#### case文

複数の条件を指定するときに、シンプルに書くことができる

```ruby
case 対象のオブジェクトや式
  when 値1
    # 値1に一致する場合の処理
  when 値2
    # 値2に一致する場合の処理
  when 値3
    # 値3に一致する場合の処理
  else
    # どれにも一致しない場合の処理
end
```

```ruby
country = 'japan'
message = 
  case country
    when 'japan'
      'こんにちは'
    when 'us'
      'Hello'
    when 'italy'
      'ciao'
    else
      '???'
  end

puts message  #=> 'こんにちは'
```

thenを使って以下のようにも書くことができるが、使用頻度は高くないらしい。個人的にはわかりやすくて好き。

```ruby
country = 'us'
message = case country
            when 'japan' then 'こんにちは' 
            when 'us' then 'Hello'
            when 'italy' then 'ciao'
            else '???'
          end
puts message  #=> 'Hello'
```



#### 条件演算子(三項演算子)

シンプルなif/elseであれば、スッキリ書けるが、複雑な場合は読みづらくなることがあるとのこと、確かに。

```ruby
n = 11
message = n > 10 ? '10より大きい' : '10以下'
puts message  #=> '10より大きい'
```



## 配列・繰り返し処理

### 配列

Pythonでいうところのリスト

```ruby
# 空の配列を作る
a = []
puts a  #=> []
puts a.class  #=> Array
```



配列の各要素を取得する方法も基本的にはpythonと同じそう。

```ruby
a = [1, 2, 3]
# 1つ目の要素を取得
puts a[0]  #=> 1
puts a[1]  #=> 2
puts a[2]  #=> 3
```

存在しない要素を指定してもエラーにはならず、nilが返る。

```ruby
a = [1, 2, 3]
a[100]  #=> nil
```

個人的にはエラーが出て欲しいところ。

```ruby
a = [1, 2, 3]
a.size  #=> 3
a.length  #=> 3
```



#### 要素の変更、追加、削除

```ruby
a = [1, 2, 3]
a[1] = 20
puts a
```

元の大きさよりも大きい添字を指定すると、間の値がnilで埋められる。

```ruby
a = [1, 2, 3]
a[5] = 50
puts a  #=> [1, 2, 3, nil, nil, 50]
```

使う場面が想像できない。エラーにした方が保守性が高い気もするけどどうなんだろう。

`<<`を使うと配列の最後に要素を追加することができる。pythonでいうところのappend。

```ruby
a = [1, 2, 3]
a << 50
puts a  #=> [1, 2, 3, 50]
a << 100
a << 150
puts a  #=> [1, 2, 3, 50, 100, 150]
```

配列内の特定の位置にある要素を削除したい場合はdelete_atメソッドを使う。

```ruby
a = [1, 2, 3, 50, 100, 150]
# 2番目の要素を削除する(削除した値が戻り値になる)
a.delete_at(1)  #=> 2
puts a  #=> [1, 3, 50, 100, 150]

# 存在しない添字を指定するとnilが返る
a.delete_at(100)  #=> nil
puts a  #=> [1, 3, 50, 100, 150]
```



### ブロック

ブロックはメソッドの引数として渡すことができる処理のかたまりのこと。ブロック内で記述した処理は必要に応じてメソッドから呼び出される。

#### Rubyの繰り返し処理

　Rubyにもfor文はあるが、ほとんどのRubyプログラマはfor文を使わないらしい。Rubyの場合はforのような構文で繰り返し処理をさせるのではなく、配列自身に対して「繰り返せ」という命令を送る。

``` ruby
numbers = [1, 2, 3, 4]
sum = 0
numbers.each do | n |
  sum += n
end
puts sum  #=> 10
```

  eachメソッドの役割は配列の要素を最後まで順番に取り出すことです。取り出した要素をどう扱うのかは、そのときの要件で変わってくる。そこで登場するのがブロックである。配列の要素を順番に取り出す作業はeachメソッドで行い、その要素をどう扱うかはブロックに記述する。上記でいうと、doからendまでがブロックになる。

   `| n |`の`n`はブロック引数と呼ばれるもので、eachメソッドから渡された配列の要素が入る。



#### do ... end と{}

Rubyの文法上、改行を入れなくてもブロックは動作する。

```ruby
numbers = [1, 2, 3, 4]
sum = 0

# do ... endの代わりに{}を使う
numbers.each {| n | sum += n}
puts sum  #=> 10
```



### ブロックを使う配列のメソッド

#### delete_if

`delete_if`メソッドは各要素に対してブロックを評価して、値が真であれば、ブロックに渡した要素を配列から削除する。

```ruby
numbers = [1, 2, 3, 1, 2, 3]
del_numbers = numbers.delete_if { | n | n.odd?}
puts del_numbers  #=> [2, 2]
```



#### map/collect

mapメソッドは各要素に対してブロックを評価した結果を新しい配列にして返す。

```ruby
numbers = [1, 2, 3, 4, 5]
# ブロックの戻り値が新しい配列の各要素になる
new_numbers = numbers.map {| n | n * 10}
puts new_numbers  #=> [10, 20, 30, 40, 50]
```



#### select/find_all/reject

selectメソッドは各要素に対してブロックを評価し、その戻り値が真の要素を集めた配列を返すメソッドである。

```ruby
numbers = [1, 2, 3, 4, 5, 6]
# ブロックの戻り値が真になった要素だけが集められる
even_numbers = numbers.select { | n | n.even? }
puts even_numbers  #=> [2, 4, 6]
```

rejectメソッドはselectメソッドの反対で、ブロックの戻り値が真になった要素を除外した配列を作成する。

```ruby
numbers = [1, 2, 3, 4, 5, 6]
# 3の倍数を除外する(3の倍数以外を集める)
non_multiples_of_three = numbers.reject {| n | n % 3 == 0}
puts non_multiples_of_three  #=> [1, 2, 4, 5]
```



#### find/detect

findメソッドはブロックの戻り値が真になった最初の要素を返す。

```ruby
numbers = [1, 2, 3, 4, 5, 6]
# ブロックの戻り値が最初に真になった要素を返す
even_number = numbers.find { |n| n.even? }
puts even_number  #=> 2
```



#### inject/reduce

injectメソッドは畳み込み演算を行うメソッドである。

```ruby
numbers = [1, 2, 3, 4]
sum = 0
numbers.each { | n | sum += n}
puts sum  #=> 10
```

上のコードはinjectメソッドを使うと次のように書くことができる。

```ruby
numbers = [1, 2, 3, 4]
sum = numbers.inject(0) { | result, n | result + n}
puts sum  #=> 10
```

ブロックの第一引数(上記コードのresult)は初回のみinjectメソッドの引数(上記のコードでは0)が入る。2回目以降は前回のブロックの戻り値が入る。 ブロックの第二引数(上記コードのn)は配列の各要素が順番い入る。ブロックの戻り値は次の回に引き継がれ、ブロックの第一引数(result)に入る。繰り返し処理が最後まで終わると、ブロックの戻り値がinjectメソッドの戻り値になる。

- 1回目: result = 0, n = 1で、0+1=1。これが次のresultに入る
- 2回目: result = 1, n = 2で、1+2=3。これが次のresultに入る
- 3回目: result = 3, n = 3で、3+3=6。これが次のresultに入る
- 4回目: result = 6, n = 4で、6+4=10。最後の要素に達したのでこれがinjectメソッドの戻り値になる。



## 基礎知識系

#### ガベージコレクション

　使用されなくなったオブジェクトを回収し、自動的にメモリを開放してくれる機能がRubyには備わっている。



#### エイリアスメソッド

　Rubyにはまったく同じメソッドに複数の名前がついている場合があるらしい。

```ruby
# length, size
'hello'.length  #=> 5
'hello'.size  #=> 5
```

意味があるのだろうか？



#### 式(Expression)と文(statement)

 Rubyではほかの言語では文と見なされるような要素が式になっていることが多い。

式: 値を返し、結果を変数に代入できるもの
文: 値を返さず、変数に代入しようとすると構文エラーになるもの 

上記で分類すると、Rubyのif文やメソッド定義は文ではなく、式になっている。

```ruby
a = 
  if true
    '真'
  else
    '偽'
  end
puts a  #=> 真

b = def foo; end
puts b  #=> foo
```

参考
[プロを目指す人のためのRuby入門](https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AERuby%E5%85%A5%E9%96%80-%E8%A8%80%E8%AA%9E%E4%BB%95%E6%A7%98%E3%81%8B%E3%82%89%E3%83%86%E3%82%B9%E3%83%88%E9%A7%86%E5%8B%95%E9%96%8B%E7%99%BA%E3%83%BB%E3%83%87%E3%83%90%E3%83%83%E3%82%B0%E6%8A%80%E6%B3%95%E3%81%BE%E3%81%A7-Software-Design-plus-ebook/dp/B077Q8BXHC/ref=sr_1_5?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&dchild=1&keywords=ruby&qid=1619601472&sr=8-5)