Yuki's Tech Blog

仕事で得た知見や勉強した技術を書きます。

最近知ったRubyのメソッドについてまとめる

目次

概要

最近知ったRubyのメソッドをまとめます。 Rubyのメソッドを知る過程で知った、Ruby以外の知識もまとめます。

最近知ったRubyのメソッド

Enumerable#tally

docs.ruby-lang.org

docs.ruby-lang.org

tallyメソッドは、self に含まれる要素を数え上げた結果を Hash で返します。Hashのキーが数え上げ対象の要素で、valueが要素の出現回数です。 ちなみに、tallyは多動詞で、「集計する」という意味です。

このメソッドを使うことで、以下のような配列の重複要素を数え上げる処理が簡潔に書くことができます。

↓ before

    # @param [Array<Integer>] numbers
    # @return [Integer]
    def get_unique_number(numbers)
      number_counter = Hash.new(0)
      numbers.each { |number| number_counter[number] += 1 }
      unique_numbers = number_counter.filter { |_, count| count == 1 }.keys
      unique_numbers[0]
    end

↓ after(keyメソッドを使うことで、valueが1のkeyを取得できます)

    # @param [Array<Integer>] numbers
    # @return [Integer]
    def get_unique_number(numbers)
      numbers.tally.key(1)
    end

Enumerable#all?

docs.ruby-lang.org

Enumerable#all?は、すべての要素が条件を満たす場合に true を返します。偽である要素があれば、ただちに false を返します。 このall?を使うことで、以下の処理を簡潔に書くことができます。

↓ before

# @param [Array<Array<Integer>>] matrix
# @return [Boolean]
def square_matrix?(matrix)
  row_count = matrix.length
  matrix.each do |numbers|
    return false unless numbers.length == row_count
  end

  true
end

↓ after

# @param [Array<Array<Integer>>] matrix
# @return [Boolean]
def square_matrix?(matrix)
  row_count = matrix.length
  matrix.all? { |numbers| numbers.length == row_count }
end

Array#transpose

docs.ruby-lang.org

transposeメソッドを使うことで、selfを行列と見立てて、行列の転置(行と列の入れ換え)を行います。転置した配列を生成して返します(生成するので、このメソッドは破壊的ではない)。空の配列に対しては空の配列を生成して返します。

irb
irb(main):001:0> a = [[1, 2, 3], [3, 5, 5]]
irb(main):003:0> a.transpose
=> [[1, 3], [2, 5], [3, 5]]
irb(main):004:0> a
=> [[1, 2, 3], [3, 5, 5]]
irb(main):005:0>

Array#concat

docs.ruby-lang.org

Array#concatメソッドを使うことで、selfの末尾に引数の配列を破壊的に追加します。この際に気をつけるのが、配列自体を要素として、selfに追加されるわけではなく、引数の配列は展開されて、selfに追加されます。ちなみに、concatは、concatenateの略で、concatenateは他動詞で、「~を連結させる」という意味です。

irb(main):005:0> a = [1, 2, 3]
irb(main):006:0> b = [4, 5, 5]
irb(main):007:0> a.concat(b)
=> [1, 2, 3, 4, 5, 5]
irb(main):008:0> a
=> [1, 2, 3, 4, 5, 5]
irb(main):009:0> b
=> [4, 5, 5]
irb(main):010:0>

配列から要素を追加、取得系のメソッド

破壊的、非破壊的の観点からまとめていきます。

破壊的

配列に破壊的に要素を追加するなら、push/unshiftを使います。 配列から破壊的に要素を取得する、pop/shiftを使います。

Array#pushメソッドは、指定された objを順番に配列の末尾に破壊的に追加します。

docs.ruby-lang.org

irb(main):001:0> a = [1, 2, 3]
irb(main):002:0> a.push(5)
=> [1, 2, 3, 5]
irb(main):003:0> a
=> [1, 2, 3, 5]
irb(main):004:0> a.push([6, 6])
=> [1, 2, 3, 5, [6, 6]]
irb(main):005:0> a
=> [1, 2, 3, 5, [6, 6]]
irb(main):001:0> a = [1, 2, 3]
irb(main):002:0> a.push(1, 2)
=> [1, 2, 3, 1, 2]
irb(main):022:0> a = [1, 2, 3]
irb(main):023:0> a.push([1, 2])
=> [1, 2, 3, [1, 2]]
irb(main):024:0> a.push(*[1, 2])
=> [1, 2, 3, [1, 2], 1, 2]
irb(main):001:0> a = [1, 2, 3]
# 配列を展開して追加するなら、concatを使う方が綺麗
irb(main):002:0> a.push(*[1, 2])
=> [1, 2, 3, 1, 2]
irb(main):003:0> a.concat([5, 6])
=> [1, 2, 3, 1, 2, 5, 6]

Array#unshiftは、指定された obj を引数の最後から順番に配列の先頭に破壊的に挿入します。Array#pushとArray#unshiftの違いは、pushは配列の末尾に要素を追加するのに対して、unshiftは配列の先頭に要素を追加します。

docs.ruby-lang.org

irb(main):001:0> a = [1, 2, 3]
irb(main):002:0> a.push(1, 2)
=> [1, 2, 3, 1, 2]
irb(main):003:0> a = [1, 2, 3]
irb(main):004:0> a.unshift(1)
=> [1, 1, 2, 3]
irb(main):005:0> a.unshift(1, 2)
=> [1, 2, 1, 1, 2, 3]
irb(main):006:0> a.unshift(8)
=> [8, 1, 2, 1, 1, 2, 3]
irb(main):007:0> a.unshift(9, 10)
=> [9, 10, 8, 1, 2, 1, 1, 2, 3]
irb(main):014:0> a.unshift([2, 3])
=> [[2, 3], 9, 1, 2, 3]
irb(main):015:0> a.unshift(*[2, 3])
=> [2, 3, [2, 3], 9, 1, 2, 3]

Array#popは、自身の末尾から要素を破壊的に取り除いて、その要素を返します。引数を指定した場合はその個数だけ取り除き、それを配列で返します。

docs.ruby-lang.org

irb(main):004:0> a = [1, 2, 3]
irb(main):005:0> a.pop
=> 3
irb(main):006:0> a
=> [1, 2]
irb(main):007:0> a.push(3)
=> [1, 2, 3]
irb(main):008:0> a
=> [1, 2, 3]
irb(main):009:0> a.pop(2)
=> [2, 3]
irb(main):010:0> a = [1, [2, 3], 4]
irb(main):011:0> a.pop
=> 4
irb(main):012:0> a
=> [1, [2, 3]]
irb(main):013:0> a.pop
=> [2, 3]
irb(main):014:0> a
=> [1]

Array#shiftは、配列の先頭の要素を破壊的に取り除いて、その要素を返します。引数を指定した場合はその個数だけ取り除き、それを配列で返します。

docs.ruby-lang.org

irb(main):001:0> a = [1, 2]
irb(main):002:0> a.shift
=> 1
irb(main):003:0> a
=> [2]
irb(main):004:0> a = [1, [2, 3], 5]
irb(main):005:0> a.shift
=> 1
irb(main):006:0> a
=> [[2, 3], 5]
irb(main):007:0> a.shift
=> [2, 3]
irb(main):008:0> a
=> [5]
irb(main):011:0> a
=> [5]
irb(main):012:0> a.push([1, 2])
=> [5, [1, 2]]
irb(main):013:0> a.shift(2)
=> [5, [1, 2]]
irb(main):014:0> a
=> []

これらの配列の破壊的メソッドをいつ使うかを表にまとめます。

配列に要素を追加する 配列から要素を取り出す
先頭 unshift shift
末尾 push pop

この表から、 配列の先頭に要素を追加したいなら、unshift 配列の要素を先頭から取り出したいなら、shift (shiftはずらすって意味だから、前の要素がずれて取り出せるってイメージでなんとなくメソッドの動作が理解できる) 配列の末尾に要素を追加したいなら、push 配列の要素を末尾から取り出したいなら、pop

を使えば良いということが分かりました。

非破壊的

配列を破壊的に操作したいなら、まずはその配列のコピーを作ることが大事です。そのような場合、スプラット演算子を使いましょう。

yukihaga.hatenablog.com

irb
irb(main):001:0> a = [1, 2, 3]
irb(main):002:0> a
=> [1, 2, 3]
irb(main):003:0> a.push(1, 2)
=> [1, 2, 3, 1, 2]
irb(main):004:0> a
=> [1, 2, 3, 1, 2]
irb(main):005:0> a = [1, 2, 3]
irb(main):006:0> [*a].push(4)
=> [1, 2, 3, 4]
irb(main):007:0> a
=> [1, 2, 3]
irb(main):008:0> [*a, 4]
=> [1, 2, 3, 4]
irb(main):009:0> [*a].shift
=> 1
irb(main):010:0> a
=> [1, 2, 3]
irb(main):011:0> [*a].unshift(3)
=> [3, 1, 2, 3]
irb(main):012:0> a
=> [1, 2, 3]
irb(main):013:0> [3, *a]
=> [3, 1, 2, 3]
irb(main):014:0> a
=> [1, 2, 3]
irb(main):015:0> [*a, 4]
=> [1, 2, 3, 4]
irb(main):016:0> a
=> [1, 2, 3]
irb(main):017:0> [*a].push(4)
=> [1, 2, 3, 4]
irb(main):018:0> a
=> [1, 2, 3]
irb(main):019:0> [*a].pop
=> 3
irb(main):020:0> a
=> [1, 2, 3]
irb(main):021:0>

ファイルは改行で終わらす

unixでは、テキスト・ファイルは一連の行で構成され、それぞれの行は改行文字( \n)で終わる。したがって、空でなく改行で終わらないファイルはテキスト・ファイルではない。

テキスト・ファイルを操作することを想定したユーティリティは、改行で終わらないファイルにうまく対処できないかもしれません

unix.stackexchange.com

ファイルに書いた一連の行は改行文字で終わらせる方が良いので、そのため、ファイルには改行が含まれているそうです。 これはunixの規約なので、必ずしも守る必要はないですが、Github上で赤くマイナスが表示される時は、ファイルの末尾に改行が含まれていない指摘です。

終わり

Rubyに関して色々メソッドが知れてよかったです。 また、この機会で、配列を操作する系のメソッドも整理できて良かったです。

参考記事