配列 (Array) オブジェクト
- 配列名は、英単語の複数形にする
- △ :
fruit = ["apple", "banana", "grape", "peach"]
- ○ :
fruits = ["apple", "banana", "grape", "peach"]
- △ :
fruits = ["apple", "banana", "grape", "peach"]
puts fruits[-1] # peach
puts fruits[-2] # grape
- 配列の範囲外の要素を指定すると
nil
が返る
l = [1, 2, 3]
p l[5] # nil
- オブジェクトに対して直接メソッドを呼び出す
- これは
3.to_s
や5.times
なども同じ仕組み
- これは
l = [1, 2, 3]
p l.last
p [1, 2, 3].last
先頭と末尾の要素を取得 first
last
fruits = ["apple", "banana", "grape", "peach"]
puts fruits.first # apple
puts fruits.last # peach
要素の追加・削除
要素を追加 unshift
push
<<
メソッド
unshift
: 先頭に追加push
<<
: 末尾に追加
l = [2, 3]
p l.push(4) # [2, 3, 4]
p l.unshift(1) # [1, 2, 3, 4]
p l << 5 # [1, 2, 3, 4, 5]
要素を削除 shift
pop
メソッド
shift
: 先頭を削除pop
: 末尾を削除
l = [1, 2, 3, 4, 5]
l.pop
p l # [1, 2, 3, 4]
l.shift
p l # [2, 3, 4]
pop
shift
は削除した要素を返す
l = [1, 2, 3, 4, 5]
p l.pop # 5
p l # [1, 2, 3, 4]
p l.shift # 1
p l # [2, 3, 4]
ネスト構造の配列に複数の配列を追加
- 以下のように書くのは冗長
parent = []
child_1 = [1, 2, 3]
child_2 = [4, 5, 6]
child_3 = [7, 8, 9]
parent << child_1
parent << child_2
parent << child_3
p parent
# [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
- 以下のように書くとスッキリ
parent = []
child_1 = [1, 2, 3]
child_2 = [4, 5, 6]
child_3 = [7, 8, 9]
parent += [child_1, child_2, child_3]
p parent
# [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
- 要素を取りまとめるために新規の(親)配列を作るなら、いきなり代入すればよい
child_1 = [1, 2, 3]
child_2 = [4, 5, 6]
child_3 = [7, 8, 9]
parent = [child_1, child_2, child_3]
p parent
# [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
配列の足し算 / 引き算
足し算
- 配列をつなげた新しい配列を返す
l1 = [1, 2, 3]
l2 = [4, 5, 6]
p l1 + l2 # [1, 2, 3, 4, 5, 6]
引き算
- もとの配列から要素を取り除いた新しい配列を返す
- 「もとの配列だけにある要素を得る」際に便利
l1 = [1, 2, 3]
l2 = [4, 1, 3]
p l1 - l2 # [2]
size
/ length
(要素の数をカウント)
l = [1, 2, 3]
p l.size # 3
p l.length # 3
sum
(配列の要素の合計値を計算)
l = [1, 2, 3]
p l.sum # 6
- 配列内の数字の平均値を求める
l = [1, 2, 4]
p l.sum / l.size # 2
sort
(並び替え)
- 昇順に並び替え
p [4, 2, 8].sort
# [2, 4, 8]
- 文字列の場合、アルファベット順にソートされる
p ["banana", "grape", "apple"].sort
# ["apple", "banana", "grape"]
- 大文字を含むと、大文字が優先されてソートされる
p ["Banana", "grape", "apple"].sort
# ["Banana", "apple", "grape"]
reverse
(逆順に並び替え)
- 単純に配列の並び順を逆にする
p [4, 2, 8, 5].reverse
# [5, 8, 2, 4]
sort
とメソッドチェーンにすることで、降順に並び替え
p [4, 2, 8, 5].sort.reverse
# [8, 5, 4, 2]
文字列を逆順に
- 文字列の並びを逆にすることもできる
p
で表示すると、日本語がエンコードされた
p "abc".reverse
# "cba"
p "ひらがな".reverse
# "\u306A\u304C\u3089\u3072"
p "漢字".reverse
# "\u5B57\u6F22"
- ファイルの冒頭で下記を宣言するとOKな様子
Encoding.default_internal = __ENCODING__
Encoding.default_internal = __ENCODING__
p "abc".reverse
# "cba"
p "ひらがな".reverse
# "ながらひ"
p "漢字".reverse
# "字漢"
puts
で出力すると問題はない
puts "abc".reverse
# cba
puts "ひらがな".reverse
# ながらひ
puts "漢字".reverse
# 字漢
join
(配列の要素を連結 → 文字列にする)
["apple", "banana", "grape"]
を"apple & banana & grape"
として出力したい場合- 単に配列をループで回しても意図した通りにならない
- 最後の配列の要素にも
&
が付与されるため、条件分岐するなどもうひと手間が必要になる
- 最後の配列の要素にも
l = ["apple", "banana", "grape"]
result = ""
l.each { |t| result += t + " & " }
p result
# "apple & banana & grape & "
join
メソッドを使うと簡単に表現できる- 引数
- 「メソッドへ渡すオブジェクトのこと」
- 引数に区切り文字を入れる
- 区切り文字によって連結される
- 引数なし
- 区切りなしでそのまま連結される
- 引数
l = ["apple", "banana", "grape"]
p l.join(" & ")
# "apple & banana & grape"
p l.join
# "applebananagrape"
- 配列の要素が 1 つでも意図した通りに動く
l = ["apple"]
p l.join(" & ")
# "apple"
split
(文字列を分割 → 配列にする)
l = "apple banana grape"
p l.split
# ["apple", "banana", "grape"]
l = "apple & banana & grape"
p l.split(" & ")
# ["apple", "banana", "grape"]
map
(配列の各要素を変換 → 新たな配列を作る)
l = [1, 2, 3]
result = l.map do |n|
n * 2
end
p result
# [2, 4, 6]
l = [100, 200, 300]
result = l.map do |n|
"#{n} yen"
end
p result
# ["100 yen", "200 yen", "300 yen"]
do
~end
を省略した記法
l = [100, 200, 300]
result = l.map { |n| "#{n} yen" }
p result
# ["100 yen", "200 yen", "300 yen"]
★シンボル
を使った簡略記法
- 「ブロック内で特定のメソッドを呼び出すだけの場合(←重要)」に限り、
シンボル
を使った簡略記法もある- 以下は
result = l.map { |t| t.reverse }
と等価
- 以下は
l = ["apple", "banana", "grape"]
result = l.map(&:reverse)
# result = l.map { |t| t.reverse }
p result
# ["elppa", "ananab", "eparg"]
each
と map
の違い
- 「戻り値」の違い
each
→ 元の配列のままmap
→ 処理結果を反映した配列を返す
l = [1, 2, 3]
r1 = l.each { |n| n * 2 }
p r1
# [1, 2, 3]
r2 = l.map { |n| n * 2 }
p r2
# [2, 4, 6]
each
で処理結果を反映した配列を得ようとすると- 空の配列を用意 → ループを回して格納していく必要がる
l = [1, 2, 3]
r = []
l.each { |n| r << n * 2 }
p r
- eachは繰り返し処理に使う
- mapは繰り返し処理の結果を配列にしたいときに使う
break
で処理を中断
l = [1, 2, 3]
l.each do |n|
break if n == 2
p n
end
next
で処理をスキップ
l = [1, 2, 3]
l.each do |n|
next if n == 2
p n
end
# 1
# 3
範囲 Range
l = (3..5)
puts l
# 3..5
puts l.class
# Range
l.each {|i| p i}
# 3
# 4
# 5
配列のスライス
l = [1, 2, 3, 4, 5]
p l[1..3]
# [2, 3, 4]
p l[2..-1]
# [3, 4, 5]
多重配列
ループ
each
を入れ子にする方法があるが
array = [[1,2,3], [4,5,6], [7,8,9]]
array.each do |ary|
ary.each do |elm|
puts elm
end
end
ブロック引数に複数指定すると中の配列の要素がそのまま取り出せる
array = [[1,2,3], [4,5,6], [7,8,9]]
array.each do |elm1, elm2, elm3|
puts elm1, elm2, elm3
end
# 1, 2, 3, 4, 5, 6, 7, 8, 9
zip
メソッド
p [1,2,3].zip([4,5,6], [7,8,9])
# [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
任意の要素を基準にソート sort_by
sort
でも実現できるが、sort_by
を使った方が感覚的に分かりやすい- 処理速度も
sort_by
の方が良さげ
l = [[1, 3, 185, 4], [5, 4, 64, 2], [2, 4, 504, 8]]
p l.sort_by {|x| x[2] }.reverse
# [[2, 4, 504, 8], [1, 3, 185, 4], [5, 4, 64, 2]]