:pぴー.sendせんど(:pぴー, :pぴー)

mokoaki
mokoriso@gmail.com

2017/07/22

Array 配列

Ruby技術者認定試験の書籍写経メモ

配列の生成

リテラル

これを使えばおk

a = [1, 2, 3]

a.class
=> Array

Array.[] に要素を渡すと配列が作成される

この方法は積極的に使う理由がない限り使いません

Array[1 , 2, 3]
=> [1, 2, 3]

Array.newに数値を渡すと、指定したサイズの “全ての要素がnilの配列” が作成される

この方法は積極的に使う理由がない限り使いません

Array.new(3)
=> [nil, nil, nil]

Array.newに配列を渡すと、渡した配列が複製されます

a = ['a', 'b', 'c']

c = Array.new(a)

a.object_id
=> 70321659644240
c.object_id
=> 70321659578860

a[1].object_id
=> 70321654905680
c[1].object_id
=> 70321654905680

Array.newに数値とオブジェクトを渡すと、指定したサイズの “全ての要素が指定したオブジェクトな配列” が作成される

この動作が本当に必要な場面はあまりないだろう

a = 'moko'
a.object_id
=> 70271478704800

as = Array.new(3, a)
=> ["moko", "moko", "moko"]

as[0].object_id
=> 70271478704800
as[1].object_id
=> 70271478704800

Array.newに数値とブロックを渡すとイテレート毎にオブジェクトが作られ、それを指す配列が作成される

as = Array.new(3) { 'moko' }
=> ["moko", "moko", "moko"]

as[0].object_id
=> 70271479084700
as[1].object_id
=> 70271479084680
Array.new(3) { |index| "moko#{index}" }
=> ["moko0", "moko1", "moko2"]

ハッシュに変換する

Hash#配列からハッシュへ変換

配列の添字に数値を指定して値にアクセスする

['a', 'b', 'c'][0]
=> "a"

値を設定する場合には破壊的に変更する・・という事は当然、同じオブジェクトを指している変数からも変更後のオブジェクトが参照されるという事である。一応書いとく

a = ['a', 'b', 'c']
b = a

a[1] = 'z'

a
=> ["a", "z", "c"]

b
=> ["a", "z", "c"]

要素数よりも大きな値が指定された場合には自動的に配列の長さが伸長される

a = ['a', 'b', 'c']
a[10] = 'z'
a
=> ["a", "b", "c", nil, nil, nil, nil, nil, nil, nil, "z"]

配列の添字に2つ数値を指定すると[開始場所、長さ]の指定となる

[0, 1, 2, 3, 4][2, 3]
=> [2, 3, 4]

多重代入、可変長代入 ここは熱い!

a, b = 10, 20
a #=> 10
b #=> 20

配列でもいい、というか下記するが、もともと配列として処理される

a, b = [10, 20]
a #=> 10
b #=> 20

メソッドの戻り値でも使える

def hage
  return 10, 20 # さすがにreturnが必要
end

hage.class # 戻り値は普通に配列
=> Array

a, b = hage
a #=> 10
b #=> 20

配列でもいい

def hage
  [10, 20]
end
a, b = hage
a #=> 10
b #=> 20

変数の数が違うと

a, b = 10, 20, 30
a #=> 10
b #=> 20

a, b, c = 10, 20
a #=> 10
b #=> 20
c #=> nil

代入先が1つなら・・これまでと同じく普通に配列として処理される

a = 10, 20, 30
a
=> [10, 20, 30]
a, *b = 1, 2, 3, 4
a #=> 1
b #=> [2, 3, 4]

右だけじゃない

*a, b = 1, 2, 3, 4
a #=> [1, 2, 3]
b #=> 4

左右だけじゃない

a, *b, c = 1, 2, 3, 4
a #=> 1
b #=> [2, 3]
c #=> 4

可変長引数は一つしか使えない

*a, *b, c = 1, 2, 3, 4
SyntaxError: (irb):155: syntax error, unexpected *

アスタだけ記述すると可変長的に引数を無視する

a, * = 1, 2, 3, 4
a #=> 1
*, a = 1, 2, 3, 4
a #=> 4
a, *, b = 1, 2, 3, 4
a #=> 1
b #=> 4
* = 1, 2, 3

代入先でカッコを使い、配列のレベルを指定できる

a, b, c = [10, 20], 30
a #=> [10, 20]
b #=> 30
c #=> nil

(a, b), c = [10, 20], 30
a #=> 10
b #=> 20
c #=> 30

代入元の配列を引数の列にする・・みたいなこれ、何ていうんだろう

a, b, c = 1, *[2, 3], *[4]
#=> [1, 2, 3, 4]
a, b, c, d = 1, *[2, 3], *[4]
#=> [1, 2, 3, 4]

以下は同じ結果になる

a, b, c =   1, 2, 3
a, b, c =  [1, 2, 3]
a, b, c = *[1, 2, 3]
a, b, c = *[1], *[2], *[3]

配列の要素を参照する

[] slice
at  
fetch  
values_at  
first  
last  
assoc  
rassoc  

[] slice

整数、Rangeオブジェクト、始点終点で指定したインデックスに対応する要素を返す

a = [1, 2, 3]

a[1]
=> 2

a[1, 2]
=> [2, 3]

a[1..2]
=> [2, 3]
a = [1, 2, 3]

a.slice(1)
=> 2

a.slice(1, 2)
=> [2, 3]

a.slice(1..2)
=> [2, 3]

at

整数でインデックスを指定できるだけ

a = [1, 2, 3]

a.at(1)
=> 2

a.at(10)
=> nil

fetch

a = [1, 2, 3]

a.fetch(1)
=> 2

a.fetch(10)
IndexError: index 10 outside of array bounds

a.fetch(10, 'aaa')
=> "aaa"

a.fetch(10) do |index|
  index + 5
end
=> 15

values_at

a = [1, 2, 3]

a.values_at(1)
=> [2] # ここが違う

a.values_at(1, 2)
=> [2, 3]

a.values_at(1..2)
=> [2, 3]

first

a = [1, 2, 3, 4, 5]

a.first
=> 1

a.first(1)
=> [1]

a.first(3)
=> [1, 2, 3]

last

a = [1, 2, 3, 4, 5]

a.last
=> 5

a.last(1)
=> [5]

a.last(3)
=> [3, 4, 5]

assoc

a = [[1, 'AAA'], [2, 'BBB'], [3, 'CCC'], [4, 'DDD']]

a.assoc('AAA')
=> nil

a.assoc(2)
=> [2, "BBB"]

rassoc

a = [[1, 'AAA'], [2, 'BBB'], [3, 'CCC'], [4, 'DDD']]

a.rassoc(2)
=> nil

a.rassoc('BBB')
=> [2, "BBB"]

配列の要素を調べる

include?
index
rindex

include?

指定された値が要素の中にあるかどうかを返します

[1, 2, 3].include?(5)
=> false

[1, 2, 3].include?(2)
=> true

index rindex

[1, 2, 3, 2, 1].index(2)
=> 1

[1, 2, 3, 2, 1].rindex(2)
=> 3

配列の要素を削除する

破壊的

delete_at  
delete_if reject!
delete  
clear  
slice!  
shift  
pop  

delete_at

指定されたインデックスに対応する要素を取り除き、その要素を返す

a = ['a', 'b', 'c', 'd']

a.delete_at(2)
=> 'c'

a
=> ["a", "b", "d"]

delete_if reject!

ブロックにて要素を評価し、結果が真になった要素を全て取り除いた自分自身を返す

a = [1, 2, 3, 4, 5]

a.delete_if do |i|
  i % 2 == 0
end
=> [1, 3, 5]

a
=> [1, 3, 5]
a = [1, 2, 3, 4, 5]

a.reject! do |i|
  i % 2 == 0
end
=> [1, 3, 5]

a
=> [1, 3, 5]

delete

全ての要素をチェックし、指定した値と==で等しい要素は全て削除

a = [1, 2, 3, 1, 2, 3]

a.delete(2)
=> 2

a
=> [1, 3, 1, 3]

clear

全ての要素を削除する もちろん object_id は変わらない

a = [1, 2, 3, 1, 2, 3]

a.object_id
=> 70254126512700

a.clear
=> []

a
=> []

a.object_id
=> 70254126512700

slice!

整数、Rangeオブジェクト、始点終点で指定したインデックスに対応する要素を削除する

a = [1, 2, 3, 4, 5]

a.slice!(1)
=> [2]

a
=> [1, 3, 4, 5]
a = [1, 2, 3, 4, 5]

a.slice!(1..2)
=> [2, 3]

a
=> [1, 4, 5]
a = [1, 2, 3, 4, 5]

a.slice!(1, 3)
=> [2, 3, 4]

a
=> [1, 5]

shift

下の方に書いてある

pop

下の方に書いてある

配列の演算

& 積集合
| 和集合
+
- 差(というより、全て削除)
* 配列を繰り返す、もしくはjoin

&& and || or は無いよ 論理演算子だからね

[1, 2, 3, 4] & [3, 4, 5, 6] #=> [3, 4]

[1, 2, 3, 4] | [3, 4, 5, 6] #=> [1, 2, 3, 4, 5, 6]

[1, 2, 3, 4] + [3, 4, 5, 6] #=> [1, 2, 3, 4, 3, 4, 5, 6]

[1, 2, 3, 4] - [3, 4, 5, 6] #=> [1, 2]
[1, 1, 3, 4] - [1, 2]       #=> [3, 4] # 1が複数個あったものが、全て削除される

[1, 2, 3, 4] * 2            #=> [1, 2, 3, 4, 1, 2, 3, 4]
[1, 2, 3, 4] * '_'          #=> "1_2_3_4" # :joinと同じ動作 マジかよ

配列の比較

== で普通に

[1, 2] == [1, 2]
=> true

[1, 2] == [1, 3]
=> false

<=> UFO演算子も使えます

[1, 3] <=> [1, 2]
=> 1

[1, 2] <=> [1, 2]
=> 0

[1, 2] <=> [1, 3]
=> -1

先頭の要素から比較されていく、ということは戦闘方面の要素の方が優先して比較されるという事でもある

[1, 99999] <=> [2, 1]
=> -1

配列の要素での繰り返し

each
each_index
cycle
reverse_each
他にも

ブロックはスコープを作るので、ブロック内部で初期化したローカル変数は外には漏れ出さない

each

ブロックに各要素を渡して処理する

[1, 2, 3].each do |item|
  p item
end
1
2
3
=> [1, 2, 3]

each_index

ブロックに各要素のインデックスを渡して処理する

['a', 'b', 'c'].each_index do |index|
  p index
end
0
1
2
=> ["a", "b", "c"]

cycle

[1, 2, 3].cycle(3) do |item|
  p item
end
1
2
3
1
2
3
1
2
3
=> nil

reverse_each

ブロックに各要素を末尾から渡して処理する

[1, 2, 3].reverse_each do |item|
  p item
end
3
2
1
=> [1, 2, 3]

配列の要素を連結

join

[1, 2, 3].join
=> "123"

[1, 2, 3].join('-')
=> "1-2-3"

[1, 2, 3] * '-'
=> "1-2-3"

to_s

, で連結して[]で括った文字列となる

[1, 'a', 3].to_s
=> '[1, "a", 3]'

配列の長さを求める

length
size
empty?
nitems
count

length size

配列の要素数を返す

[1, 2, 3].length
=> 3

[1, 2, 3].size
=> 3

empty?

配列の要素が空の場合、trueを返す

[1, 2, 3].empty?
=> false

[].empty?
=> true

nitems

筈だったが、Ruby1.9で廃止されたので次のcountメソッドで実現します

[1, nil, 2, nil, 3].count do |item|
  item.nil? == false
end
=> 3

count

引数を省略した場合は全要素の数を返す

[1, 1, 2, 2].count
=> 4

引数と同じ値の要素の数を返す

[1, 1, 2, 2].count(1)
=> 2

ブロックを取った場合は評価結果がtrueとなった要素の数を返す

[1, 1, 2, 2].count do |item|
  item % 2 == 0
end
=> 2

配列をソートする

sort sort!

[1, 5, 2, 4, 3].sort
=> [1, 2, 3, 4, 5]

ブロックが渡された場合、ブロックには2つの要素が渡され、評価結果が 正数, 0, 負の正数 のどれか、にてソートを行う

[[1, 6], [2, 5], [3, 4]].sort do |a, b|
  a[1] <=> b[1]
end
=> [[3, 4], [2, 5], [1, 6]]

もし<=>メソッドがないオブジェクトが要素にあったらエラー

a = '3'
b = '1'
c = '2'

def a.<=>(other)
  raise NoMethodError
end

tests = []

tests << a
tests << b
tests << c

tests.sort
=> NoMethodError: NoMethodError

配列を変換する

uniq uniq!    
compact compact!    
reverse reverse!    
flatten flatten!    
collect collect! map map!
shuffle shuffle!    

uniq uniq!

配列の要素の中から重複した要素を取り除きます

[1, 1, 2, 2, 3, 3].uniq
=> [1, 2, 3]

[1, 2, 3].uniq
=> [1, 2, 3]

uniq! の場合は重複する値がなかった場合、戻り値にnilを返します

a = [1, 1, 2, 2, 3, 3]
a.uniq!
=> [1, 2, 3]
a
=> [1, 2, 3]

a = [1, 2, 3]
a.uniq!
=> nil
a
=> [1, 2, 3]

compact compact!

配列の要素の中からnilを取り除きます

[1, 2, 3, nil].compact
=> [1, 2, 3]

[1, 2, 3].compact
=> [1, 2, 3]

compact! の場合は取り除く値がなかった場合、戻り値にnilを返します

a = [1, 2, 3, nil]
a.compact!
=> [1, 2, 3]
a
=> [1, 2, 3]

a = [1, 2, 3]
a.compact!
=> nil
a
=> [1, 2, 3]

reverse reverse!

配列の要素を逆順に並び替えた配列を返します

[1, 2, 3].reverse
=> [3, 2, 1]
a = [1, 2, 3]
a.reverse!
=> [3, 2, 1]
a
=> [3, 2, 1]

flatten flatten!

[1, 2, 3].flatten
=> [1, 2, 3]

[1, [2], 3].flatten
=> [1, 2, 3]

[1, [2, [3, 4], 5], 6].flatten
=> [1, 2, 3, 4, 5, 6]

[1, [2, [3, 4], 5], 6].flatten(1)
=> [1, 2, [3, 4], 5, 6]

flatten! の場合は平準化されなかった場合、戻り値にnilを返します

a = [1, 2, 3]
a.flatten!
=> nil
a
=> [1, 2, 3]

a = [1, [2], 3]
a.flatten!
=> [1, 2, 3]
a
=> [1, 2, 3]

a = [1, [2, [3, 4], 5], 6]
a.flatten!
=> [1, 2, 3, 4, 5, 6]
a
=> [1, 2, 3, 4, 5, 6]

a = [1, [2, [3, 4], 5], 6]
a.flatten!(1)
=> [1, 2, [3, 4], 5, 6]
a
=> [1, 2, [3, 4], 5, 6]

collect ollect! map map!

[1, 2, 3, 4, 5].map do |item|
  item ** 2
end
=> [1, 4, 9, 16, 25]
a = [1, 2, 3, 4, 5]

a.map! do |item|
  item ** 2
end
=> [1, 4, 9, 16, 25]

a
=> [1, 4, 9, 16, 25]

shuffle shuffle!

配列の要素をランダムにシャッフルします

[1, 2, 3, 4, 5].shuffle
=> [5, 1, 4, 3, 2]
a = [1, 2, 3, 4, 5]

a.shuffle!
=> [4, 2, 5, 1, 3]

a
=> [4, 2, 5, 1, 3]

配列の配列、多次元配列を行と列からなるデータと見立て、行と列を入れ替えた配列を返す

array.transpose

[[1, 2, 3], ['a', 'b', 'c']].transpose
=> [[1, "a"], [2, "b"], [3, "c"]]

各配列の要素数が一致しない時にはエラー

[[1, 2], ['a', 'b', 'c']].transpose
=> IndexError: element size differs (3 should be 2)
[[1, 2, 3], ['a', 'b']].transpose
=> IndexError: element size differs (2 should be 3)

配列を組み合わせて新たな配列を生成する

product
zip

array.product

自身と与えられた配列から1つずつ要素を取り、全ての組み合わせの配列を返します

[1, 2].product([3, 4])
=> [[1, 3], [1, 4], [2, 3], [2, 4]]

[1, 2, 3].product([4, 5, 6])
=> [[1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3, 4], [3, 5], [3, 6]]

引数に指定できる配列は複数個も可能

[1, 2].product([3, 4], [5, 6])
=> [[1, 3, 5], [1, 3, 6], [1, 4, 5], [1, 4, 6], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6]]

array.zip

自身と与えられた配列から1つずつ要素を取り、その組み合わせの配列を返します

[1, 2].zip(['a', 'b'])
=> [[1, "a"], [2, "b"]]

[1, 2, 3].zip(['a', 'b', 'c'])
=> [[1, "a"], [2, "b"], [3, "c"]]

引数に指定できる配列は複数個も可能

[1, 2].zip([3, 4], [5, 6])
=> [[1, 3, 5], [2, 4, 6]]

配列の長さが違う場合に自身の長さが基準となるようです

[1, 2].zip(['a', 'b', 'c'])
=> [[1, "a"], [2, "b"]]

[1, 2, 3].zip(['a', 'b'])
=> [[1, "a"], [2, "b"], [3, nil]]
[1, 2, 3].zip(['a', 'b', 'c'], ['d', 'e', 'f']) do |a, b, c|
  p a, b, c
  'test'
end
1
"a"
"d"
2
"b"
"e"
3
"c"
"f"
=> nil

配列をパックする

pack

['ruby'].pack('m')
=> "cnVieQ==\n"

"cnVieQ==\n".unpack('m')
=> ["ruby"]

['ルビー'].pack('m').unpack('m')
=> "ルビー"

配列の要素を追加したり取り出したり

破壊的

concat 複数の 配列を受け取り 配列の末尾 に配列を連結
<< 1つの オブジェクトを受け取り 配列の末尾 にオブジェクトを連結
insert 1つの オブジェクトを受け取り 第1引数で指定した場所 にオブジェクトを挿入
push 複数の オブジェクトを受け取り 配列の末尾 にオブジェクトを連結
pop     配列の末尾 からオブジェクトを指定した数だけ取り出す
shift     配列の頭 からオブジェクトを指定した数だけ取り出す
unshift 複数の オブジェクトを受け取り 配列の頭 にオブジェクトを連結

concat

配列の末尾に配列を破壊的に連結、引数はもちろん配列

a = [1, 2, 3]
a.concat(4)
TypeError: no implicit conversion of Integer into Array

a = [1, 2, 3]
a.concat([4])
a
=> [1, 2, 3, 4]

引数を省略したり、空の配列を配列を渡すと何も追加されないので注意

a = [1, 2, 3]
a.concat()
=> [1, 2, 3]

a = [1, 2, 3]
a.concat([])
=> [1, 2, 3]

<<

配列の末尾にオブジェクトを破壊的に連結、引数は1つのみ

a = [1, 2, 3]
a << 4
a
=> [1, 2, 3, 4]

a = [1, 2, 3]
a << [4]
a
=> [1, 2, 3, [4]]

a = [1, 2, 3]
a << 4, 5
SyntaxError: syntax error, unexpected ',', expecting end-of-input

引数を(むりやり)省略すると、nilが追加されるけど、まぁ覚えなくていいかと

a = [1, 2, 3]
a << ()
=> [1, 2, 3, nil]

push

配列の末尾にオブジェクトを破壊的に連結、引数は複数指定可能

a = [1, 2, 3]
a.push(4)
a
=> [1, 2, 3, 4]

a = [1, 2, 3]
a.push([4])
a
=> [1, 2, 3, [4]]

a = [1, 2, 3]
a.push(*[4, 5]) # 配列の引数展開・・キモい
=> [1, 2, 3, 4, 5]

a = [1, 2, 3]
a.push(4, 5)
=> [1, 2, 3, 4, 5]

引数を省略すると、何も追加されないので注意

a = [1, 2, 3]
a.push
=> [1, 2, 3]

pop

a = [1, 2, 3]
a.pop
=> 3
a
=> [1, 2]

a = [1, 2, 3]
a.pop(1)
=> [3]
a
=> [1, 2]

a = [1, 2, 3]
a.pop(2)
=> [2, 3]
a
=> [1]

a = [1, 2, 3]
a.pop(3)
=> [1, 2, 3]
a
=> []

a = [1, 2, 3]
a.pop(4)
=> [1, 2, 3]
a
=> []

a = []
a.pop
=> nil
a
=> []

shift

a = [1, 2, 3]
a.shift
=> 1
a
=> [2, 3]

a = [1, 2, 3]
a.shift(1)
=> [1]
a
=> [2, 3]

a = [1, 2, 3]
a.shift(2)
=> [1, 2]
a
=> [3]

a = [1, 2, 3]
a.shift(3)
=> [1, 2, 3]
a
=> []

a = [1, 2, 3]
a.shift(4)
=> [1, 2, 3]
a
=> []

a = []
a.shift
=> nil
a
=> []

unshift

配列の頭にオブジェクトを破壊的に連結、引数は複数指定可能

a = [1, 2, 3]
a.unshift(4)
a
=> [4, 1, 2, 3]

a = [1, 2, 3]
a.unshift([4])
a
=> [[4], 1, 2, 3]

a = [1, 2, 3]
a.unshift(4, 5)
=> [4, 5, 1, 2, 3]

引数を省略すると、何も追加されないので注意

a = [1, 2, 3]
a.unshift
=> [1, 2, 3]

insert

指定した場所にオブジェクトを破壊的に挿入

a = [1, 2, 3]
a.insert(1, 'a')
a
=> [1, "a", 2, 3]

a = [1, 2, 3]
a.insert(1, ['a', 'b'])
a
=> [1, ["a", "b"], 2, 3]

空の配列を指定すると、もちろん空の配列が追加される

a = [1, 2, 3]
a.insert(1, [])
a
=> [1, [], 2, 3]

引数を省略すると、何も追加されないので注意

a = [1, 2, 3]
a.insert(1)
a
=> [1, 2, 3]

配列の要素を変更する

[]

配列の添字に2つ数値を指定、代入すると指定した長さの部分が代入したオブジェクトへ置き換わる

as = [0, 1, 2, 3, 4]
as[1, 2] = '50'
as
=> [0, '50', 3, 4]

配列を渡すと元の配列より長くなったりも可能

as = [0, 1, 2, 3, 4]
as[1, 2] = ['50', '51', '53']
as
=> [0, '50', '51', '53', 3, 4]

as = [0, 1, 2, 3, 4]
as[1, 2] = '60', '61', '63'
as
=> [0, "60", "61", "63", 3, 4]

単純な挿入みたいな動きにもできる

as = [0, 1, 2, 3, 4]
as[1, 0] = ['71', '72']
as
=> [0, "71", "72", 1, 2, 3, 4]

空の配列を渡すと削除的な動きになる

as = [0, 1, 2, 3, 4]
as[1, 2] = []
as
=> [0, 3, 4]

fill

配列の全ての要素が指定したオブジェクトを指すように変更する

a = [1, 2, 3]
a.fill('z')

a
=> ["z", "z", "z"]

a[0].object_id
=> 70321654840300
a[1].object_id
=> 70321654840300

第2引数以降に始点終点、Rangeオブジェクトを指定すると当該する部分のみ変更される

a = [1, 2, 3, 4, 5]
a.fill('z', 2, 2)

a
=> [1, 2, "z", "z", 5]
a = [1, 2, 3, 4, 5]
a.fill('z', 1..3)

a
=> [1, "z", "z", "z", 5]

ブロックを取ることもでき、ブロックの評価結果で要素を変更する

a = ['a', 'b', 'c', 'd', 'e']
a.fill(2..3) do |index|
  index + 100
end

a
=> ["a", "b", 102, 103, "e"]

replace

自分自身のオブジェクトIDを変えることなく、引数で指定された配列で自分自身の内容を置き換えます

a = [1, 2, 3, 4, 5 ]
b = [6, 7, 8, 9, 10]

a
=> [1, 2, 3, 4, 5]

a.object_id
=> 70321654806640

a.replace(b)

a
=> [6, 7, 8, 9, 10]

a.object_id
=> 70321654806640