Ruby 入門

Ruby 配列

配列(Array)は、Rubyにおいて最も基礎的かつ重要なデータ構造(Data Structure)の一つであり、順序付けられたアイテムのコレクションを格納するために特化しています。配列の用途は極めて幅広く、シンプルな数値のリストから複雑なオブジェクトのコレクションまで、柔軟にハンドリングできます。

本章では、配列を作成する様々なメソッド、要素にアクセスするためのコアとなるテクニック、そしてインデックス(Index)を操作する際に注意すべき重要なポイントを網羅的に解説します。

1. 配列の作成

Rubyには配列を作成する多様なアプローチがあり、それぞれのユースケースに適しています。これらのメソッドを習得することが、配列を効率的に活用するための第一歩となります。

1.1 リテラル(Literal)表記の使用

配列を作成する最も一般的で直感的な方法は「リテラル(Literal)」表記を用いることです。カンマ区切りの要素リストをブラケット([])で囲みます。

# 空の配列
empty_array = [] 

# 数値を含む配列
number_array = [1, 2, 3, 4, 5] 

# 文字列を含む配列
string_array = ["apple", "banana", "cherry"] 

# 複数のデータ型が混在する配列
mixed_array = [1, "hello", 3.14, true] 

puts empty_array.inspect
puts number_array.inspect
puts string_array.inspect
puts mixed_array.inspect

上記のコード例において:

  • empty_array は空の配列として初期化されます。
  • number_array は整数のグループを格納します。
  • string_array は文字列のリストを含みます。
  • mixed_array は、配列が異なるデータ型の要素を格納できることを完璧に示しています。これこそが、Rubyの動的型付け(Dynamic Typing)の魅力です。

1.2 Array.new コンストラクタの使用

Array.new コンストラクタ(Constructor)は、配列を作成する際、特に特定のサイズやデフォルト値を持つ配列を初期化する必要がある場合に、より高い柔軟性を提供します。

指定サイズの配列作成

Array.new に整数のパラメータを渡すことで、特定のサイズの配列を作成できます。デフォルトでは、配列は nil 値で埋められます(Fill)。

# サイズ5の配列を作成し、nilで埋める
array_of_nils = Array.new(5)
puts array_of_nils.inspect # 出力: [nil, nil, nil, nil, nil]

デフォルト値を持つ指定サイズの配列作成

特定の値で配列を初期化するには、Array.new に配列のサイズとデフォルト値の2つのパラメータを渡します。

# サイズ3の配列を作成し、"default"という値で埋める
default_array = Array.new(3, "default")
puts default_array.inspect # 出力: ["default", "default", "default"]

重要なトラップ回避ガイド: 文字列や別の配列のようなミュータブル(Mutable)なオブジェクトをデフォルト値として使用する場合、配列内のすべての要素がメモリ上の同一のオブジェクトをポイント(Point)することになります。一つの要素を変更すると、他のすべての要素に影響が及びます。これはRuby初心者が最も陥りやすい罠です!

# ミュータブルなデフォルト値の罠を示す例
mutable_array = Array.new(3, []) # 意図: 3つの空配列を含む配列を作成
mutable_array[0] << "added"      # 最初の要素(配列)に "added" を追加
puts mutable_array.inspect       # 予期せぬ出力: [["added"], ["added"], ["added"]]

この惨事を避けるためには、ブロック(Block)と組み合わせて Array.new を使用してください。これにより、各要素に対して独立した新しいオブジェクトが作成されます。

# 正しいアプローチ: 独立したミュータブルオブジェクトを含む配列の作成
correct_array = Array.new(3) { [] } # 独立した3つの空配列を含む配列を作成
correct_array[0] << "added"         # 最初の要素に "added" を追加
puts correct_array.inspect          # 正しい出力: [["added"], [], []]

ここでは、ブロック { [] } が配列の各スロットに対して1回ずつ実行されるため、完全に新しく独立した空の配列が作成されます。

1.3 %w と %W による文字列配列の作成

Rubyは、文字列の配列を素早く作成するための非常に便利なショートハンド(Shorthand)記法として %w%W を提供しています。

  • %w は文字列配列を作成する際、特殊文字や変数をパース(Parse)しません。
  • %W は文字列内での変数展開(Interpolation)とエスケープシーケンスのパースを許可します。
# %w の使用 (スペースで区切るだけで、クォーテーションやカンマは不要)
words_array = %w[apple banana cherry]
puts words_array.inspect # 出力: ["apple", "banana", "cherry"] 

# %W を使用した変数展開
name = "Alice"
greeting_array = %W[Hello #{name}, welcome!]
puts greeting_array.inspect # 出力: ["Hello Alice,", "welcome!"] (スペース区切りのルールに注意)

1.4 他のオブジェクトを配列に変換

多くのRubyオブジェクトは、.to_a メソッドを使用して配列に変換(Convert)することができます。

# レンジ (Range) を配列に変換
range = (1..5)
range_array = range.to_a
puts range_array.inspect # 出力: [1, 2, 3, 4, 5] 

# 文字列を文字の配列に変換
string = "Ruby"
string_array = string.chars # このシナリオでは、string.to_aよりも .chars の方が一般的で効率的です
puts string_array.inspect # 出力: ["R", "u", "b", "y"]

2. 配列要素へのアクセス

配列内の要素にアクセスすることは最も基本的なオペレーションです。Rubyは、インデックス(Index)やその他の条件に基づいて要素を取得するための、柔軟なメソッドを多数提供しています。

2.1 正のインデックスによるアクセス

Rubyの配列は、ゼロベースインデックス(Zero-indexed)を採用しています。これは、最初の要素がインデックス 0 に、2番目の要素がインデックス 1 に配置されることを意味します。ブラケット [] 内にインデックスを指定することで、対応する要素にアクセスできます。

my_array = ["apple", "banana", "cherry", "date"] 

# 最初の要素にアクセス (インデックス 0)
first_element = my_array[0]
puts "最初の要素: #{first_element}" # 出力: 最初の要素: apple 

# 3番目の要素にアクセス (インデックス 2)
third_element = my_array[2]
puts "3番目の要素: #{third_element}" # 出力: 3番目の要素: cherry

2.2 負のインデックスによるアクセス(後方からの検索)

Rubyは負のインデックスをネイティブにサポートしており、配列の末尾から要素にアクセスする際に非常に便利です。-1 は最後の要素、-2 は最後から2番目の要素を表します。

my_array = ["apple", "banana", "cherry", "date"] 

# 最後の要素にアクセス (インデックス -1)
last_element = my_array[-1]
puts "最後の要素: #{last_element}" # 出力: 最後の要素: date 

# 最後から2番目の要素にアクセス (インデックス -2)
second_last_element = my_array[-2]
puts "最後から2番目の要素: #{second_last_element}" # 出力: 最後から2番目の要素: cherry

2.3 配列のスライス(Array Slicing)

配列のスライス(Slice)を使用すると、配列の一部を抽出し、それを新しい配列としてリターン(Return)することができます。インデックスの範囲(Range)を指定するか、「開始インデックス」と「長さ(Length)」を指定します。

レンジ(Range)を使用したスライス:

my_array = ["apple", "banana", "cherry", "date", "fig"] 

# インデックス1から始まり、インデックス4の直前(含まない)までの要素を抽出
slice_1 = my_array[1...4] # 3つのドット (...) は終端を含まないことを示します
puts slice_1.inspect # 出力: ["banana", "cherry", "date"] 

# インデックス1から始まり、インデックス4(含む)までの要素を抽出
slice_2 = my_array[1..4] # 2つのドット (..) は終端を含むことを示します
puts slice_2.inspect # 出力: ["banana", "cherry", "date", "fig"]

「開始インデックス」と「長さ」を使用したスライス:

my_array = ["apple", "banana", "cherry", "date", "fig"] 

# インデックス1から始まり、後方に向かって3つの要素を抽出
slice_3 = my_array[1, 3]
puts slice_3.inspect # 出力: ["banana", "cherry", "date"]

2.4 境界外アクセス

配列の境界外にある要素にアクセスしようとした場合、Rubyはプログラムをクラッシュさせたりエラーをスロー(Throw)したりすることなく、マイルドに nil をリターンします。

my_array = ["apple", "banana", "cherry"] 

# 配列のサイズを超えるインデックスへのアクセス
out_of_bounds = my_array[5]
puts out_of_bounds.inspect # 出力: nil 

# 配列の先頭を超える負のインデックスへのアクセス
out_of_bounds_negative = my_array[-5]
puts out_of_bounds_negative.inspect # 出力: nil

2.5 first および last メソッドの使用

先頭と末尾の要素に、よりセマンティック(Semantic)にアクセスするために、Rubyは非常に便利な firstlast メソッドを提供しています。

my_array = ["apple", "banana", "cherry"] 

# 最初の要素にアクセス
first_element = my_array.first
puts "最初の要素: #{first_element}" # 出力: 最初の要素: apple 

# 最後の要素にアクセス
last_element = my_array.last
puts "最後の要素: #{last_element}" # 出力: 最後の要素: cherry 

# 数値 n を渡す: 最初の n 個の要素を取得
first_two = my_array.first(2)
puts "最初の2つの要素: #{first_two}" # 出力: 最初の2つの要素: ["apple", "banana"]

注意:first(n) メソッドは、最初の n 個の要素を含む新しい配列をリターンします。

3. 配列要素の変更

配列はミュータブル(Mutable)です。つまり、作成後にそのコンテンツを自由に変更することができます。特定のインデックスに新しい値をアサイン(Assign)することで、要素を変更できます。

3.1 インデックスを通じた要素の変更

my_array = ["apple", "banana", "cherry"] 

# インデックス 1 の要素を変更
my_array[1] = "grape"
puts my_array.inspect # 出力: ["apple", "grape", "cherry"] 

# インデックス -1(最後)の要素を変更
my_array[-1] = "date"
puts my_array.inspect # 出力: ["apple", "grape", "date"]

3.2 現在のサイズを超えた要素の追加(自動スケーリング)

既存の配列サイズを超えるインデックスにアサインを行った場合、Rubyの配列は新しい要素を格納するために自動的に拡張(Auto-scaling)されます。その間の欠落したインデックス(ギャップ)には、自動的に nil がフィル(Fill)されます。

my_array = ["apple", "banana", "cherry"] 

# インデックス 5 に要素を追加(現在の配列にはインデックス 0, 1, 2 しか存在しません)
my_array[5] = "fig"
puts my_array.inspect # 出力: ["apple", "banana", "cherry", nil, nil, "fig"]

3.3 配列スライスの置換

配列内の特定のスライスを、新しい要素で直接置換することができます。新しい要素の数は、置換されるスライスのサイズと一致している必要はありません。Rubyは自動的に配列のサイズを調整(Adjust)します。

my_array = ["apple", "banana", "cherry", "date", "fig"] 

# インデックス 1 から 3 までの要素を新しい要素で置換
my_array[1..3] = ["grape", "kiwi"]
puts my_array.inspect # 出力: ["apple", "grape", "kiwi", "fig"] 

# スライスを空の配列で置換(事実上、その部分の要素を削除することと同等です)
my_array[1..2] = []
puts my_array.inspect # 出力: ["apple", "fig"]