目的
配列の要素を交互に取得し、二つの配列を作成します。
色々なやり方があるとは思いますが、私はこのような方法をとりました。
別解をいただきました。
方法
array = ['い', 'ろ', 'は', 'に', 'ほ', 'へ', 'と', 'ち', 'り', 'ぬ', 'る', 'を']
array_A = []
array_B = []
array.each_with_index { |kana, index| index.even? ? array_A << kana : array_B << kana }
p array_A
# => ["い", "は", "ほ", "と", "り", "る"]
p array_B
# => ["ろ", "に", "へ", "ち", "ぬ", "を"]
使用したメソッド
メソッド | 意味 | マニュアル |
---|---|---|
each_with_index | 各要素とそれに付随する添字(インデックス)に対し処理を繰り返す | Enumerable#each_with_index |
even? | 要素が偶数であればtrueを返す | Integer#even? |
? : | 条件演算子(三項演算子) if・else文を1行で書いたもの | 演算子式 |
<< | 配列に要素を追加する | Array#<< |
解説
まず、空の配列を準備します。
array_A = []
array_B = []
この中に元の配列array
から交互に要素を入れていきます。
そのために使ったメソッドがeach_with_index
です。
each_with_index
このメソッドは繰り返しを行うeach
メソッドに変数として各要素のインデックスを使用できるようにしたものです。
['い', 'ろ', 'は'].each_with_index { |kana, index| p "#{kana} - #{index}" }
# => "い - 0"
# "ろ - 1"
# "は - 2"
配列array
の各要素とインデックスは,
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
い | ろ | は | に | ほ | へ | と | ち | り | ぬ | る | を |
となっているため、これを利用して、インデックスが偶数の時にはarray_A
に、奇数の時にはarray_B
に要素を入れていきます。
条件分岐には条件演算子を使用しました。
? : (条件演算子)
?
の前の条件で分岐し、:
の前後で、trueの場合とfalseの場合それぞれの処理を分けています。
num = 1
num == 1 ? "これは 1 です" : "これは 1 ではありません"
# => "これは 1 です"
これは、
num = 1
if num == 1
"これは 1 です"
else
"これは 1 ではありません"
end
# => "これは 1 です"
と同じ意味になります。
そして、条件の偶数であるかどうかを確認するため、even?
メソッドを使用しました。
even?
このメソッドはレシーバ(.の左側)が偶数であればtrue
を、奇数であればfalse
を返してくれます。
2.even?
# => true
1.even?
# => false
# 0も偶数です
0.even?
# => true
ちなみに、演算子を使用した計算でも同じことができます。
num = 2
num % 2 == 0
# => true
ある数を2で割った時、余りが0であれば偶数です。
even?
でインデックスが偶数か奇数かを確認し、? :
で条件分岐したあとは、
<<
で配列に要素を足しています。
<< (追加)
<<
は配列の末端に要素を一つ追加します。
num_array = [1, 2]
num_array << 3
p num_array
# => [1, 2, 3]
@scivola 様よりご教示いただいた別解
※ 配列が偶数の場合のみです。
array = ['い', 'ろ', 'は', 'に', 'ほ', 'へ', 'と', 'ち', 'り', 'ぬ', 'る', 'を']
array_A, array_B = array.each_slice(2).to_a.transpose
p array_A
# => ["い", "は", "ほ", "と", "り", "る"]
p array_B
# => ["ろ", "に", "へ", "ち", "ぬ", "を"]
使用したメソッド
メソッド | 意味 | マニュアル |
---|---|---|
each_slice | 要素を指定の数づつ分ける | Enumerable#each_slice |
to_a | 配列を作る | Enumerable#entries |
transpose | 配列を行列に見立て、行と列を入れ替える | Array#transpose |
解説
今回はメソッドで配列が作られるため、空の配列を作る必要はありません。
まず、array_A, array_B =
。
これは多重代入(マニュアル)を使用しています。
num_A, num_B = 1, 2
p num_A
# => 1
p num_B
# => 2
このように、左辺と右辺を2つずつ用意することで、同時に代入が可能になります。
この2つの左辺に代入できる、2つの配列を作っていきます。
まずeach_slice(2)
を使用し、配列を2つずつの塊に分けています。
each_slice
このメソッドは複数の要素(配列や範囲オブジェクト)を、()
内で指定した数ずつブロック( { }内 )に渡します。
[1, 2, 3, 4, 5, 6].each_slice(2) { |n| p n }
# [1, 2]
# [3, 4]
# [5, 6]
元の配列を二つずつに分けたら、次はそれを配列にしなければなりません。そのために使用するメソッドがto_a
です。
to_a
このメソッドは、渡された要素を配列に変換します。
(1..10).to_a
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
上記は連続する(..
)、1〜10までの数字を配列に変換しています。
each_slice
は、{}
をなくすと、Enumerator
クラスのオブジェクトを返します。
[1, 2, 3, 4, 5, 6].each_slice(2)
# => #<Enumerator: [1, 2, 3, 4, 5, 6]:each_slice(2)>
to_a
メソッドはEnumerator
クラスのメソッドでもあるため、渡されたオブジェクトに使用し、配列が作成されます。
aa = [1, 2, 3, 4, 5, 6].each_slice(2)
aa.class # .classメソッドを使うと、レシーバ(.の左側)のクラスを返してくれます。
# => Enumerator
aa.to_a
# => [[1, 2], [3, 4], [5, 6]]
最後に、2つずつに分けた配列の中の配列を右側と左側で分ければ完了です。
つまり、上記の数字を例にすると、
[[ 1, 2 ],[ 3, 4 ],[ 5, 6 ]]
のように赤の数字の配列と青の数字の配列に分けることができれば、元の配列を交互に取得して、二つの配列を作成したことになります。
そのためのメソッドがtranspose
です。
transpose
このメソッドは配列の中の配列を行列に見立て、行と列を入れ替えます。
[[0, 1], [0, 1], [0, 1]].transpose
# => [[0, 0, 0], [1, 1, 1]]
先程の赤と青の数字で例えると、
赤 | 青 |
---|---|
1 | 2 |
3 | 4 |
5 | 6 |
が、
赤 | 1 | 3 | 5 |
---|---|---|---|
青 | 2 | 4 | 6 |
となるようなイメージです。
これで2つの配列ができたため、多重代入でそれぞれの変数に代入されます。
@jnchito 様よりご教示いただいた別解
array = ['い', 'ろ', 'は', 'に', 'ほ', 'へ', 'と', 'ち', 'り', 'ぬ', 'る', 'を']
array_A, array_B = array.partition.with_index { |_, index| index.even? }
p array_A
# => ["い", "は", "ほ", "と", "り", "る"]
p array_B
# => ["ろ", "に", "へ", "ち", "ぬ", "を"]
使用したメソッド
メソッド | 意味 | マニュアル |
---|---|---|
partition | 各要素を条件分岐し、2つの配列を作成する。 | Enumerable#partition |
with_index | 繰り返し処理の変数に、インデックスが使えるようになる。 | Enumerator#with_index |
even? | 要素が偶数であればtrueを返す | Integer#even? |
解説
今回もメソッドで配列が作られるため、変数に配列の定義は必要ありません。
さらに多重代入で、2つの配列を同時に代入します。
そして、その二つの配列を作るためのメソッドがpartition
です。
partition
このメソッドは、配列の各要素をブロック( { }内 )の条件を満たすか否かで2つの配列に分けます。
[1, 2, 3, 4, 5].partition { |num| (num % 2) == 0 }
# => [[2, 4], [1, 3, 5]]
このメソッドを使用して、偶数の場合とそれ以外(奇数)の場合の配列を作ります。
しかし、partition
メソッドが使用できるブロックの変数は、要素の変数しか使用できません。(上記の場合、num
の部分)
今回、偶数・奇数を判断したいのは要素に付随する添字(index
)の値です。
そのために必要になるメソッドがwith_index
です。
with_index
このメソッドは、本来index
が変数として使用できない繰り返し処理(map
メソッド等)に、index
を使用できるようにするものです。
['い', 'ろ', 'は'].map.with_index { |kana, index| "#{index}-#{kana}" }
# => ["0-い", "1-ろ", "2-は"]
これを利用して、index
が偶数の場合と奇数の場合をeven?
で判断し、2つの配列を作成します。
even? (odd?)
このメソッドは先も出た通り、レシーバ(.の左側)が偶数であればtrue
を、奇数であればfalse
を返してくれます。
ちなみに、odd?
というメソッドもあり、これはeven?
の逆になります。
レシーバが奇数であればtrue
を、偶数であればfalse
を返してくれます。
1.odd?
# => true
2.odd?
# => false
変数 _
今回、partition.with_index
のブロックで使用する変数はindex
のみで、要素は使用しません。そのため、要素の変数を_
にしています。
array.partition.with_index { |_, index| index.even? }
参考:変数名やブロックパラメーターをアンダースコア1文字にするイディオム - Qiita
最後に
さらに良い方法がございましたら、ご教示いただけますと幸です。
ご覧いただき、ありがとうございました。