第1章: 文字列と配列の基本操作
range.to_a - 範囲オブジェクトから配列を作る
# 0から5までの整数を配列にする
arr = (0..5).to_a
p arr
# [0, 1, 2, 3, 4, 5]
# 0から4まで(5は含まない)
arr = (0...5).to_a
p arr
# [0, 1, 2, 3, 4]
Array.new - 指定した要素数で配列を作る
# 要素数5のnil入り配列を作る
arr = Array.new(5)
p arr
# [nil, nil, nil, nil, nil]
# 初期値を設定して作る
arr = Array.new(5, 0)
p arr
# [0, 0, 0, 0, 0]
# Array.new + 連番(indexをそのまま使う)
arr = Array.new(5) { |i| i }
p arr
# [0, 1, 2, 3, 4]
# ブロックを使って、インデックスを元に値を入れる
arr = Array.new(5) { |i| i * 2 }
p arr
# [0, 2, 4, 6, 8]
Array.newのネスト - 二次元配列を作る
# ▼ 間違った二次元配列(全て同じオブジェクトを参照)
arr1 = Array.new(3, Array.new(2, 0))
arr1[0][0] = 1
puts "arr1(NGパターン: 同じ参照)"
p arr1
# => [[1, 0], [1, 0], [1, 0]]
# ▼ 正しい二次元配列(ブロックで個別に作成)
arr2 = Array.new(3) { Array.new(2, 0) }
arr2[0][0] = 1
puts "\narr2(OK: 各行を別々に生成)"
p arr2
# => [[1, 0], [0, 0], [0, 0]]
# ▼ 各行にインデックスを使う
arr4 = Array.new(3) { |i| [i, i] }
puts "\narr4(インデックスを使った初期化)"
p arr4
# => [[0, 0], [1, 1], [2, 2]]
# ▼ 二重ループ的な初期化
arr8 = Array.new(3) do |i|
Array.new(4) do |j|
"#{i},#{j}"
end
end
puts "\narr8(二重ループでインデックス表示)"
p arr8
# => [["0,0", "0,1", "0,2", "0,3"], ["1,0", "1,1", "1,2", "1,3"], ["2,0", "2,1", "2,2", "2,3"]]
split - 文字列を区切って配列にする
# 一単語ずつ区切る
sentence = "programming"
words = sentence.split("")
p words
# ["p", "r", "o", "g", "r", "a", "m", "m", "i", "n", "g"]
str = "apple,banana,grape"
arr = str.split(",")
p arr
# => ["apple", "banana", "grape"]
# 単語をスペースで区切る例
sentence = "I love Ruby programming"
words = sentence.split(" ")
p words
# => ["I", "love", "Ruby", "programming"]
chars - 文字列を1文字ずつ配列化
str = "hello"
arr = str.chars
p arr
# => ["h", "e", "l", "l", "o"]
join - 配列を文字列に結合する
arr = ["apple", "banana", "grape"]
str = arr.join(",")
p str
# => "apple,banana,grape"
gsub - 文字列の一括置換
str = "a-b-c"
new_str = str.gsub("-", ",")
p new_str
# => "a,b,c"
# そのパターンにマッチした部分を全部 / に置き換える例
# 正規表現で -+(1個以上のハイフン)にマッチ
str = "a--b---c"
new_str = str.gsub(/-+/, "/")
p new_str
# => "a/b/c"
slice - 文字列から取り出す
str = "programming"
puts str[0, 3] # => pro
puts str[0, 4] # => prog
puts str[1, 5] # => rogra
puts str[2, 5] # => ogram
puts str[-3, 3] # => ing 最後の三文字を取り出す
puts str[-5, 5] # => mming 最後の五文字を取り出す
/
と %
- 割り算と余りを求める演算子
# 時間と分の変換によく使う!
# 125分を「時間+分」に分解したいとき
minutes = 125
# 時間を取り出す(60分で割る)
hours = minutes / 60
p hours
# 2
# 残りの分(余り)を取り出す
remain = minutes % 60
p remain
# 5
total_seconds = 367
minutes = total_seconds / 60
seconds = total_seconds % 60
puts "#{minutes}分#{seconds}秒"
# => 6分7秒
基本的なインデックスアクセス
arr = [10, 20, 30, 40, 50]
puts arr[0]
puts arr[1]
puts arr[2]
puts arr[3]
puts arr[4]
puts arr[5]
puts arr[-1]
puts arr[-2]
# => 10
# => 20
# => 30
# => 40
# => 50
# =>
# => 50
# => 40
length - 要素数や長さ
numbers = [1, 2, 3, 4, 5]
puts numbers.length # => 5
text = "Hello"
puts text.length # => 5
hash = { a: 1, b: 2 }
puts hash.length # => 2
min, max - 配列の最小, 最大の取得
numbers = [3, 1, 7, 4, 9]
p numbers.min # => 1
p numbers.max # => 9
numbers2 = [8, 5, 3, 10, 1, 7]
p numbers2.min(2) # => [1, 3]
p numbers2.max(3) # => [10, 8, 7]
include? - 含まれているかを調べる
str = "programming"
puts str.include?("pro") # => true "pro" が含まれている
puts str.include?("gram") # => true "gram" が含まれている
puts str.include?("mming") # => true "mming" が含まれている
puts str.include?("xyz") # => false "xyz" は含まれていない
puts str.include?("Pro") # => false 大文字小文字は区別される
puts str.include?("pg") # => false "pg" は含まれていない
arr = [1, 2, 3, 4, 5]
puts arr.include?(3) # => true
puts arr.include?(6) # => false
times - 指定した回数だけ繰り返す
# インデックスを使わず単純に繰り返す(|i| 省略)
3.times do
puts "Hello!"
end
# => Hello!
# => Hello!
# => Hello!
5.times do |i|
puts i * 2
end
# => 0
# => 2
# => 4
# => 6
# => 8
# インデックスを使って配列を作る
arr = []
4.times do |i|
arr << i * 10
end
p arr
# => [0, 10, 20, 30]
# ネストして2次元配列を作る
board = []
3.times do |i|
row = []
4.times do |j|
row << "#{i},#{j}"
end
board << row
end
p board
# => [["0,0", "0,1", "0,2", "0,3"], ["1,0", "1,1", "1,2", "1,3"], ["2,0", "2,1", "2,2", "2,3"]]
# 条件付きで分岐
5.times do |i|
if i.even?
puts "#{i} is even"
else
puts "#{i} is odd"
end
end
# => 0 is even
# => 1 is odd
# => 2 is even
# => 3 is odd
# => 4 is even
each - 配列の全要素を処理
[1, 2, 3].each do |n|
puts n * 2
end
# => 2
# => 4
# => 6
each_with_index - 要素とインデックスを同時に扱う
["a", "b", "c"].each_with_index do |val, idx|
puts "#{idx}: #{val}"
end
# => 0: a
# => 1: b
# => 2: c
map - 各要素を変換して新しい配列を作る
nums = [1, 2, 3]
doubled = nums.map { |n| n * 2 }
p doubled
# => [2, 4, 6]
nums = [1, 2, 3, 4, 5]
odd_or_even = nums.map do |n|
n.even? ? "even" : "odd"
end
p odd_or_even
# => ["odd", "even", "odd", "even", "odd"]
# インデックス付きで変換したい場合(each_with_indexと組み合わせ)
words = ["apple", "banana", "cherry"]
numbered = words.each_with_index.map do |word, i|
"#{i + 1}. #{word}"
end
p numbered
# => ["1. apple", "2. banana", "3. cherry"]
# 文字列を大文字に変換
names = ["alice", "bob", "charlie"]
upper = names.map(&:upcase)
p upper
# => ["ALICE", "BOB", "CHARLIE"]
# map - timesと組み合わせて配列生成(0〜4の2乗)
squares = 5.times.map { |i| i ** 2 }
p squares
# => [0, 1, 4, 9, 16]
# ネストした配列を変換(2次元配列)
matrix = [[1, 2], [3, 4], [5, 6]]
doubled = matrix.map { |row| row.map { |n| n * 2 } }
p doubled
# => [[2, 4], [6, 8], [10, 12]]
第2章: 標準入力と繰り返し処理
first(n) - 配列の先頭n件を取得
arr = [10, 20, 30, 40, 50]
p arr.first(3)
# => [10, 20, 30]
map(&:to_i) - 文字列配列を整数配列に変換
strs = ["1", "2", "3"]
ints = strs.map(&:to_i)
p ints
# => [1, 2, 3]
gets - 標準入力から1行取得 (改行文字 \n
が入るので注意)
input = gets
p input
text # 自分で入力
"text\n" # 出力結果
chomp - 改行を除去
input = gets.chomp
p input
text # 自分で入力
"text" # 出力結果
実用例: 複数数値の入力を整数配列に変換
nums = gets.chomp.split.map(&:to_i)
# 別の書き方
# nums = gets.chomp.split.map { |num| num.to_i }
p nums
10 20 30 # 自分で入力
[10, 20, 30] # 出力結果
第3章: 配列の応用と重複処理
sort - 昇順にソート
arr = [5, 1, 3]
p arr.sort
# => [1, 3, 5]
reverse - 配列の並びを逆順に
arr = [1, 2, 3]
p arr.reverse
# => [3, 2, 1]
uniq - 重複を取り除く
arr = [1, 2, 2, 3, 1]
p arr.uniq
# => [1, 2, 3]
a & b - 配列同士の共通部分(AND)
a = [1, 2, 3, 6, 8]
b = [2, 3, 4, 7, 8]
p a & b
# => [2, 3, 8]
c = [1, 2, 3]
d = [2, 3, 4]
e = [3, 4, 5]
p c & d & e
# => [3]
<< , push - 配列へ要素を追加
arr = [1, 2]
arr << 3
p arr
# => [1, 2, 3]
arr = [1, 2]
arr.push(3)
p arr
# => [1, 2, 3]
zip - 配列をペア化する
a = [1, 2, 3]
b = ["a", "b", "c"]
zipped = a.zip(b)
p zipped
# => [[1, "a"], [2, "b"], [3, "c"]]
第4章: ハッシュ操作と変換テクニック
配列にインデックスを付けてハッシュ化
to_h
- [key, value] のペアの配列として解析した結果を Hash にして返す。
arr = ["apple", "banana", "grape"]
hash = arr.each_with_index.to_h
p hash
# => {"apple"=>0, "banana"=>1, "grape"=>2}
配列をキー、別配列を値としてハッシュに変換(zip + to_h)
keys = ["a", "b", "c"]
values = [1, 2, 3]
hash = keys.zip(values).to_h
p hash
# => {"a"=>1, "b"=>2, "c"=>3}
ハッシュの各ペアを繰り返し処理
hash = {a: 1, b: 2, c: 3}
hash.each do |key, val|
puts "#{key} => #{val}"
end
# => a => 1
# => b => 2
# => c => 3
ハッシュからキーだけ・値だけ取得
hash = {a: 1, b: 2}
p hash.keys # => [:a, :b]
p hash.values # => [1, 2]
merge - ハッシュをマージする(重複キーは上書き)
h1 = {a: 1, b: 2}
h2 = {b: 3, c: 4}
p h1.merge(h2)
# => {:a=>1, :b=>3, :c=>4}
第5章 例題を解いてみよう
例題1: 配列に3の倍数が何個あるか? 最小の3の倍数も出力
# 問題:
# 数値の配列が与えられたとき、3の倍数がいくつあるかを数えて、その中で最小の値も出力してください。
# 3の倍数が1つもない場合は "No multiples of 3" と表示してください。
arr = [5, 7, 10, 12, 15, 20]
# 解答:
multiples = []
arr.each do |n|
if n % 3 == 0
multiples << n
end
end
if multiples.length > 0
puts "Count: #{multiples.length}"
puts "Min: #{multiples.min}"
else
puts "No multiples of 3"
end
# => Count: 2
# => Min: 12
例題2: 連続する文字をグループ判定して返す
# 問題:
# 文字列が与えられたとき、同じ文字が2回以上連続している部分を判定し、
# その文字を1つずつ配列として返してください(重複は除く)。
# 例: "aabbbcdeffggh" → ["a", "b", "f", "g"]
# 1文字しか出現していないものは除外してください。
# 一度でも2文字以上連続していれば、その文字は1回だけ結果に含めます。
str = "aabbbcdeffggh"
chars = str.chars
groups = []
current = chars[0]
(1...chars.size).each do |i|
if chars[i] == current[-1]
current += chars[i]
else
groups << current
current = chars[i]
end
end
groups << current # 最後のグループを追加
# if文で2文字以上のグループだけ格納(select使わない)
result = []
groups.each do |g|
if g.size >= 2
result << g[0]
end
end
# 重複除去
result = result.uniq
p result
# => ["a", "b", "f", "g"]
例題3: 昇順ソート後、隣との差が2以上の数字を抽出
# 問題:
# 昇順に並べた後、前の要素との数値の差が2以上である要素のみを出力してください(最初の要素は除く)。
arr = [1, 5, 2, 6, 10]
# 解答:
sorted = arr.sort
result = []
(1...sorted.size).each do |i|
if sorted[i] - sorted[i - 1] >= 2
result << sorted[i]
end
end
p result
# => [5, 10]
例題4: 入力された文字列が回文かどうか判定
# 問題:
# 入力された文字列が前から読んでも後ろから読んでも同じ(回文)かどうかを判定し、結果を出力してください。
str = "racecar"
# 解答:
if str == str.reverse
puts "Palindrome"
else
puts "Not palindrome"
end
# => Palindrome
例題5: 最頻出と最少出現の要素を求めよう
# 問題:
# 配列の中で「最も多く出現した要素」と「最も少ない回数しか出現していない要素」をそれぞれ表示してください。
# 出力形式は以下の通りとします:
#
# dog appears 3 times ← 最も多い
# bird appears 1 time ← 最も少ない(1つだけ表示)
arr = ["dog", "cat", "dog", "dog", "bird", "cat"]
# 出現回数を数える
freq = arr.tally
# => {"dog"=>3, "cat"=>2, "bird"=>1}
# 最も多い要素
most_common = freq.max_by { |_, count| count }
p most_common # => ["dog", 3]
# 最も少ない要素
least_common = freq.min_by { |_, count| count }
p least_common # => ["bird", 1]
puts "#{most_common[0]} appears #{most_common[1]} times"
puts "#{least_common[0]} appears #{least_common[1]} time#{'s' if least_common[1] > 1}"
# => dog appears 3 times
# => bird appears 1 time
例題6: 条件付きインデックス+文字数チェック+ソート
# 問題:
# 以下のような文字列配列があります。
# 配列にインデックスを付けてハッシュ(値 => インデックス)に変換し、
# 次の2つの条件を満たす要素だけを取り出して新しい配列として出力してください:
#
# 条件:
# - インデックスが奇数である
# - 単語の文字数が5文字以上である
#
# さらに、その結果をアルファベット順にソートして表示してください。
#
# 例:
# ["apple", "banana", "kiwi", "grape", "orange", "plum"]
#
# ハッシュ:
# {"apple"=>0, "banana"=>1, "kiwi"=>2, "grape"=>3, "orange"=>4, "plum"=>5}
#
# → インデックスが奇数: "banana", "grape", "plum"
# → 文字数5文字以上: "banana"
# → ソート: ["banana"]
words = ["apple", "grape", "kiwi", "banana", "orange", "plum"]
# ハッシュ化(値 => インデックス)
word_hash = words.each_with_index.to_h
# 複数条件を満たす単語だけを result に入れる
result = []
word_hash.each do |word, index|
if index % 2 == 1 && word.length >= 5
result << word
end
end
# アルファベット順に並べる
result = result.sort
p result
# => ["banana", "grape"]
例題7: 以下の配列内で最も多く出現する名前を出力するプログラムを作成してください。
arr = ["sato", "suzuki", "takahashi", "suzuki", "suzuki"]
答え
arr = ["sato", "suzuki", "takahashi", "suzuki", "suzuki"]
count = Hash.new(0)
arr.each do |item|
count[item] += 1
end
puts count.key(count.values.max)
# => suzuki
例題8: 毎日の研究室の在室時間から、合計の時間と分を計算してください。
# 入力(複数行):
# 1行目に日数 N が与えられます。続く N 行に、各日の「入室時刻」と「退室時刻」が hh:mm の形式で与えられます。
5
07:15 17:09
11:10 23:00
13:11 17:20
00:59 08:10
08:43 16:53
# 出力:
合計の在室時間を「H M」(H時間 M分)の形式で出力してください。
答え
def calc_total_time(lines)
n = lines.shift.to_i
total_minutes = 0
n.times do
entry, exit = lines.shift.split
entry_h, entry_m = entry.split(':').map(&:to_i)
exit_h, exit_m = exit.split(':').map(&:to_i)
entry_total = entry_h * 60 + entry_m
exit_total = exit_h * 60 + exit_m
total_minutes += (exit_total - entry_total)
end
total_hours = total_minutes / 60
remain_minutes = total_minutes % 60
puts "#{total_hours} #{remain_minutes}"
end
# 入力例
input = <<~DATA
5
07:15 17:09
11:10 23:00
13:11 17:20
00:59 08:10
08:43 16:53
DATA
lines = input.lines.map(&:strip)
calc_total_time(lines) # => 41 14
終わりに
こちらの記事は自身がコーディング問題を解いていて、必要だと感じたメソッドや知識を随時整理して更新していきます。
株式会社シンシアでは、実務未経験のエンジニアの方や学生エンジニアインターンを採用し一緒に働いています。
※ シンシアにおける働き方の様子はこちら
弊社には年間100人程度の実務未経験の方に応募いただき、技術面接を実施しております。
この記事が少しでも学びになったという方は、ぜひ wantedly のストーリーもご覧いただけるととても嬉しいです!