コレクション
Ruby
Array・Hash・Range・Enumerable
Array
作成・操作・Enumerable メソッド
# 作成
arr = [1, 2, 3, 4, 5]
arr = Array.new(5, 0) # [0,0,0,0,0]
arr = Array.new(5) { |i| i * 2 } # [0,2,4,6,8]
arr = %w[apple banana cherry] # ['apple','banana','cherry']
arr = %i[foo bar baz] # [:foo,:bar,:baz]
# アクセス
arr[0] # 最初
arr[-1] # 最後
arr[1..3] # [2,3,4] (範囲)
arr[1, 2] # [2,3] (start, length)
arr.first # 最初の要素
arr.first(3) # 最初の3要素
arr.last # 最後の要素
arr.sample # ランダムに1つ
arr.sample(3) # ランダムに3つ
# 追加・削除
arr.push(6) # 末尾追加
arr << 7 # 末尾追加(<<演算子)
arr.unshift(0) # 先頭追加
arr.pop # 末尾削除・返却
arr.shift # 先頭削除・返却
arr.delete(3) # 値で削除(全て)
arr.delete_at(0) # インデックスで削除
arr.compact # nil を除いた新配列
arr.flatten # ネストを平坦化
arr.flatten(1) # 1段階だけ平坦化
arr.uniq # 重複排除
# 変換
arr.map { |x| x * 2 } # 変換(collect も同義)
arr.select { |x| x.even? } # 絞り込み(filter も同義)
arr.reject { |x| x.even? } # 除外
arr.reduce(0) { |sum, x| sum + x } # 畳み込み(inject も同義)
arr.reduce(:+) # シンボルで演算子を指定
arr.each_with_object([]) { |x, memo| memo << x * 2 }
arr.flat_map { |x| [x, x * 2] } # map + flatten(1)
arr.zip([10,20,30]) # [[1,10],[2,20],[3,30]]
arr.each_slice(2).to_a # [[1,2],[3,4],[5]]
arr.each_cons(3).to_a # [[1,2,3],[2,3,4],[3,4,5]]
arr.group_by { |x| x % 3 } # {1=>[1,4], 2=>[2,5], 0=>[3]}
arr.tally # 出現回数 {1=>1,2=>1,...}
arr.sort # 昇順
arr.sort_by { |x| -x } # カスタムソート(降順)
arr.min; arr.max
arr.min_by { |x| x.abs }; arr.max_by { |x| x.abs }
arr.sum; arr.count; arr.any? { |x| x > 3 }; arr.all? { |x| x > 0 }Hash
作成・操作・変換・マージ
# 作成
hash = { name: 'Alice', age: 30 } # シンボルキー(推奨)
hash = { 'name' => 'Alice', 1 => :one } # ハッシュロケット(文字列・数値キー)
hash = Hash.new(0) # デフォルト値付き
# アクセス
hash[:name] # 'Alice'
hash[:missing] # nil(KeyError は出ない)
hash.fetch(:name) # 'Alice'
hash.fetch(:missing) # KeyError!
hash.fetch(:missing, 'N/A') # デフォルト値
hash.fetch(:missing) { |k| "#{k} not found" } # ブロック
# 更新
hash[:email] = 'alice@example.com' # 追加・更新
hash.merge!(age: 31) # 破壊的マージ
hash.delete(:email) # 削除して返却
hash.reject! { |k, v| v.nil? } # 条件で削除
# 確認
hash.key?(:name) # true(has_key? も同義)
hash.value?('Alice') # true(has_value? も同義)
hash.any? { |k, v| v.is_a?(Integer) }
hash.all? { |k, v| v }
hash.count { |k, v| v.is_a?(String) }
# イテレーション
hash.each { |key, val| puts "#{key}: #{val}" }
hash.each_with_object({}) { |(k, v), memo| memo[k] = v.to_s }
# 変換
hash.keys # [:name, :age]
hash.values # ['Alice', 30]
hash.to_a # [[:name,'Alice'],[:age,30]]
hash.map { |k, v| [k, v.to_s] }.to_h
hash.transform_keys(&:to_s) # キーを変換
hash.transform_values(&:to_s) # 値を変換
hash.filter_map { |k, v| [k, v * 2] if v.is_a?(Integer) }
hash.select { |k, v| v.is_a?(String) } # 絞り込み
hash.reject { |k, v| v.nil? } # 除外
# マージ
defaults = { role: 'user', active: true }
override = { role: 'admin' }
merged = defaults.merge(override) # overrideが優先
merged = defaults.merge(override) { |key, old, new_val| new_val } # ブロックで解決Range と Enumerable
範囲オブジェクトと便利なメソッド集
# Range
(1..10) # 1から10まで(10を含む)
(1...10) # 1から9まで(10を含まない)
('a'..'z') # 文字の範囲
(1.0..3.0) # 浮動小数点
(1..10).to_a # [1,2,3,...,10]
(1..10).sum # 55
(1..10).include?(5) # true
(1..10).cover?(5) # true(数値の範囲に対して高速)
# 範囲と case
case age
when 0..17 then '未成年'
when 18..64 then '成人'
when 65.. then '高齢者' # 下限のみの範囲
end
# Enumerable モジュールが提供するメソッド
nums = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3]
nums.find { |x| x > 4 } # 5(最初の1つ)
nums.count { |x| x > 4 } # 4
nums.sum { |x| x * 2 } # 78
nums.minmax # [1, 9]
nums.minmax_by { |x| -x } # [9, 1]
nums.each_with_index { |v, i| puts "#{i}: #{v}" }
nums.map.with_index { |v, i| "#{i}:#{v}" }
nums.chunk { |x| x > 3 }.to_a
# [[false,[3,1]],[true,[4]],[false,[1]],[true,[5,9]],...]
nums.lazy.select { |x| x.odd? }.map { |x| x**2 }.first(3)
# 遅延評価: 必要な分だけ処理
# Comparable モジュール
class Temperature
include Comparable
attr_reader :degrees
def initialize(d) = (@degrees = d)
def <=>(other) = degrees <=> other.degrees
end
t1 = Temperature.new(20)
t2 = Temperature.new(30)
t1 < t2 # true
[t2, t1].sort # [t1, t2](昇順)
t1.clamp(Temperature.new(15), Temperature.new(25)) # t1