module Enumerable

[edit]

要約

繰り返しを行なうクラスのための Mix-in。このモジュールのメソッドは全て each を用いて定義されているので、インクルードするクラスには each が定義されていなければなりません。

Array, Hash, Range, Enumerator等のクラスで、 Enumerableモジュールはインクルードされています。ただし、効率化のため、そのクラスでEnumerableと同名・同等の機能を再定義(オーバーライド)しているケースも少なくなく、特にArrayクラスでは同名のメソッドを再定義していることが多いです。

目次

インスタンスメソッド

インスタンスメソッド

all? -> bool[permalink][rdoc][edit]
all? {|item| ... } -> bool
all?(pattern) -> bool

すべての要素が真である場合に true を返します。偽である要素があれば、ただちに false を返します。

ブロックを伴う場合は、各要素に対してブロックを評価し、すべての結果が真である場合に true を返します。ブロックが偽を返した時点で、ただちに false を返します。

自身に要素が存在しない場合は true を返します。

[PARAM] pattern:
ブロックの代わりに各要素に対して pattern === item を評価します。


require 'set'

# すべて正の数か?
p Set[5,  6, 7].all? {|v| v > 0 }      # => true
p Set[5, -1, 7].all? {|v| v > 0 }      # => false
p Set[].all? {|v| v > 0 }              # => true

p Set['ant', 'bear', 'cat'].all?(/t/)  # => false

[SEE_ALSO] Array#all?

any? -> bool[permalink][rdoc][edit]
any? {|item| ... } -> bool
any?(pattern) -> bool

すべての要素が偽である場合に false を返します。真である要素があれば、ただちに true を返します。

ブロックを伴う場合は、各要素に対してブロックを評価し、すべての結果が偽である場合に false を返します。ブロックが真を返した時点で、ただちに true を返します。

自身に要素が存在しない場合は false を返します。

[PARAM] pattern:
ブロックの代わりに各要素に対して pattern === item を評価します。


require 'set'
p Set[1, 2, 3].any? {|v| v > 3 }         # => false
p Set[1, 2, 3].any? {|v| v > 1 }         # => true
p Set[].any? {|v| v > 0 }                # => false
p Set['ant', 'bear', 'cat'].any?(/d/)    # => false
p Set[nil, true, 99].any?(Integer)       # => true
p Set[nil, true, 99].any?                # => true
p Set[].any?                             # => false

[SEE_ALSO] Array#any?

chain(*enums) -> Enumerator::Chain[permalink][rdoc][edit]

自身と enums 引数を続けて繰り返す Enumerator::Chain を返します。



e = (1..3).chain([4, 5])
e.to_a #=> [1, 2, 3, 4, 5]

[SEE_ALSO] Enumerator#+

chunk {|elt| ... } -> Enumerator[permalink][rdoc][edit]

要素を前から順にブロックで評価し、その結果によって要素をチャンクに分けた(グループ化した)要素を持つ Enumerator を返します。

ブロックの評価値が同じ値が続くものを一つのチャンクとして取り扱います。すなわち、ブロックの評価値が一つ前と異なる所でチャンクが区切られます。

返り値の Enumerator は各チャンクのブロック評価値と各チャンクの要素を持つ配列のペアを各要素とします。そのため、eachだと以下のようになります。


enum.chunk {|elt| key }.each {|key, ary| do_something }

例として、整数列を連続する奇数/偶数に分ける例を見てみます。「n.even?」の値が切り替わるところで区切られているのがわかるでしょう。



[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunk {|n|
  n.even?
}.each {|even, ary|
  p [even, ary]
}
# => [false, [3, 1]]
#    [true, [4]]
#    [false, [1, 5, 9]]
#    [true, [2, 6]]
#    [false, [5, 3, 5]]

このメソッドは各要素が既にソートされている場合に便利です。

以下の例では、テキスト辞書ファイルに含まれる単語の頭文字の頻度を調べています。このファイルは、Linux や macOS などで、ソートされた英語(など)の単語のリストを改行で区切って収めたものです。大文字/小文字の違いを無視するため upcase しています。



# ファイルのエンコーディングは実際のファイルに合わせてください。
open("/usr/share/dict/words", "r:iso-8859-1") {|f|
  f.chunk {|line| line[0].upcase }.each {|ch, lines| p [ch, lines.length] }
}
# => ["A", 17096]
#    ["B", 11070]
#    ["C", 19901]
#    ["D", 10896]
#    ...

さらにこのメソッドは以下の値を特別扱いします。

  • ブロックの評価値が nil もしくは :_separator であった場合、 その要素を捨てます。チャンクはこの前後で区切られます。
  • ブロックの評価値 :_alone であった場合はその要素は 単独のチャンクをなすものと解釈されます。

それ以外のアンダースコアで始まるシンボルを指定した場合は例外が発生します。



[1, 2].chunk { |item| :_underscore }.to_a
# => RuntimeError: symbols beginning with an underscore are reserved

# 「.to_a」無しだと Enumerator を返すのみで例外は発生しない

nil、 :_separator はある要素を無視したい場合に用います。例として svn log の出力のハイフンの所で区切りたい場合を考えます。



sep = "-"*72 + "\n" # ハイフンが72個の行
IO.popen("svn log README") {|f|
  f.chunk {|line|
    line != sep || nil
  }.each {|_, lines|
    pp lines
  }
}
#=> ["r20018 | knu | 2008-10-29 13:20:42 +0900 (Wed, 29 Oct 2008) | 2 lines\n",
#    "\n",
#    "* README, README.ja: Update the portability section.\n",
#    "\n"]
#   ["r16725 | knu | 2008-05-31 23:34:23 +0900 (Sat, 31 May 2008) | 2 lines\n",
#    "\n",
#    "* README, README.ja: Add a note about default C flags.\n",
#    "\n"]
#   ...

テキストを空行で区切られた段落に分けたい場合にも nil が使えます。



File.foreach("README").chunk {|line|
  /\A\s*\z/ !~ line || nil
}.each {|_, lines|
  pp lines
}

「:_alone」は要素を素通ししたい場合に用います。以下の例では「Foo#bar」という形式の行が連続している場合のみチャンク化し、それ以外は素通しします。



pat = /\A[A-Z][A-Za-z0-9_]+\#/
open(filename) {|f|
  f.chunk {|line| pat =~ line ? $& : :_alone }.each {|key, lines|
    if key != :_alone
      print lines.sort.join('')
    else
      print lines.join('')
    end
  }
}
[EXCEPTION] RuntimeError:
予約されている値を用いた場合に発生します
chunk_while {|elt_before, elt_after| ... } -> Enumerator[permalink][rdoc][edit]

要素を前から順にブロックで評価し、その結果によって要素をチャンクに分けた(グループ化した)要素を持つEnumerator を返します。

隣り合う値をブロックパラメータ elt_before、elt_after に渡し、ブロックの評価値が偽になる所でチャンクを区切ります。

ブロックは self の長さ - 1 回呼び出されます。

[RETURN]
チャンクごとの配列をブロックパラメータに渡す Enumerator を返します。eachメソッドは以下のように呼び出します。
  enum.chunk_while { |elt_before, elt_after| bool }.each { |ary| ... }
to_a や map などのその他の Enumerable モジュールのメソッドも有用です。


# 1ずつ増加する部分配列ごとに分ける。
a = [1,2,4,9,10,11,12,15,16,19,20,21]
b = a.chunk_while {|i, j| i+1 == j }
p b.to_a # => [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
p c # => [[1, 2], [4], "9-12", [15, 16], "19-21"]
d = c.join(",")
p d # => "1,2,4,9-12,15,16,19-21"

# 増加のみの部分配列ごとに分ける。
a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5]
p a.chunk_while {|i, j| i <= j }.to_a
# => [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]

# 隣り合う偶数同士、奇数同士の部分配列ごとに分ける。
# (Enumerable#chunk を使って実現する事も可能)
a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0]
p a.chunk_while {|i, j| i.even? == j.even? }.to_a
# => [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]

Enumerable#slice_when はブロックの戻り値が真ではなく偽の時に要素を分ける事を除いて同じ処理を行います。

[SEE_ALSO] Enumerable#slice_when, Enumerable#chunk

collect -> Enumerator[permalink][rdoc][edit]
map -> Enumerator
collect {|item| ... } -> [object]
map {|item| ... } -> [object]

各要素に対してブロックを評価した結果を全て含む配列を返します。

ブロックを省略した場合は Enumerator を返します。



# すべて 3 倍にした配列を返す
p (1..3).map {|n| n * 3 }  # => [3, 6, 9]
p (1..3).collect { "cat" } # => ["cat", "cat", "cat"]

[SEE_ALSO] Hash#to_h, Array#collect, Array#map

flat_map -> Enumerator[permalink][rdoc][edit]
collect_concat -> Enumerator
flat_map {| obj | block } -> Array
collect_concat {| obj | block } -> Array

各要素をブロックに渡し、その返り値を連結した配列を返します。

ブロックの返り値は基本的に配列を返すべきです。

ブロックを省略した場合は Enumerator を返します。



[[1,2], [3,4]].flat_map{|i| i.map{|j| j*2}} # => [2,4,6,8]
compact -> Array[permalink][rdoc][edit]

self から nil を取り除いた配列を生成して返します。


def with_nils
  yield 1
  yield 2
  yield nil
  yield 3
end

to_enum(:with_nils).compact # => [1, 2, 3]

[SEE_ALSO] Array#compact

count -> Integer[permalink][rdoc][edit]
count(item) -> Integer
count {|obj| ... } -> Integer

レシーバの要素数を返します。

引数を指定しない場合は、レシーバの要素数を返します。このとき、要素数を一つずつカウントします。

引数を一つ指定した場合は、レシーバの要素のうち引数に一致するものの個数をカウントして返します(一致は == で判定します)。

ブロックを指定した場合は、ブロックを評価して真になった要素の個数をカウントして返します。

[PARAM] item:
カウント対象となる値。


enum = [1, 2, 4, 2].each
enum.count                  # => 4
enum.count(2)               # => 2
enum.count{|x|x%2==0}       # => 3

[SEE_ALSO] Array#count

cycle(n=nil) -> Enumerator[permalink][rdoc][edit]
cycle(n=nil) {|obj| ... } -> object | nil

Enumerable オブジェクトの各要素を n 回 or 無限回(n=nil)繰り返しブロックを呼びだします。

n に 0 もしくは負の値を渡した場合は何もしません。繰り返しが最後まで終了した場合(つまりbreakなどで中断しなかった場合) は nil を返します。このメソッドは内部の配列に各要素を保存しておくため、一度 Enumerable の終端に到達した後に自分自身を変更してもこのメソッドの動作に影響を与えません。



a = ["a", "b", "c"]
a.cycle {|x| puts x }  # print, a, b, c, a, b, c,.. forever.
a.cycle(2) {|x| puts x }  # print, a, b, c, a, b, c.

ブロックを省略した場合は、n 回 or 無限回 enum の各要素を繰り返す Enumerator を返します。

[RETURN]
ブロックを指定しなかった場合は、Enumerator を返します。レシーバが空の場合は nil を返します。
find(ifnone = nil) -> Enumerator[permalink][rdoc][edit]
detect(ifnone = nil) -> Enumerator
find(ifnone = nil) {|item| ... } -> object
detect(ifnone = nil) {|item| ... } -> object

要素に対してブロックを評価した値が真になった最初の要素を返します。

真になる要素が見つからず、ifnone も指定されていないときは nil を返します。真になる要素が見つからず、ifnone が指定されているときは ifnone を call した結果を返します。

ブロックを省略した場合は Enumerator を返します。

[PARAM] ifnone:
call メソッドを持つオブジェクト (例えば Proc) を指定します。


# 最初の 3 の倍数を探す
p [1, 2, 3, 4, 5].find {|i| i % 3 == 0 }   # => 3
p [2, 2, 2, 2, 2].find {|i| i % 3 == 0 }   # => nil

# ifnone の使用例
ifnone = proc { raise ArgumentError, "item not found" }
p [1, 2, 3, 4, 5].find(ifnone) {|i| i % 7 == 0 }
    # ArgumentError: item not found
drop(n) -> Array[permalink][rdoc][edit]

Enumerable オブジェクトの先頭の n 要素を捨てて、残りの要素を配列として返します。

[PARAM] n:
捨てる要素数。


e = [1, 2, 3, 4, 5, 0].each
e.drop(3)             # => [4, 5, 0]

[SEE_ALSO] Array#drop

drop_while -> Enumerator[permalink][rdoc][edit]
drop_while {|element| ... } -> Array

ブロックを評価して最初に偽となった要素の手前の要素まで捨て、残りの要素を配列として返します。

ブロックを指定しなかった場合は、Enumerator を返します。



a = [1, 2, 3, 4, 5, 0]
a.drop_while {|i| i < 3 }   # => [3, 4, 5, 0]
each_cons(n) -> Enumerator[permalink][rdoc][edit]
each_cons(n) {|list| ... } -> self

要素を重複ありで n 要素ずつに区切り、ブロックに渡して繰り返します。

ブロックを省略した場合は重複ありで n 要素ずつ繰り返す Enumerator を返します。

[PARAM] n:
ブロックに渡す要素の数です。正の整数を与えます。要素数より大きな数を与えると、ブロックは一度も実行されません。


(1..10).each_cons(3){|v| p v }
# => [1, 2, 3]
#    [2, 3, 4]
#    [3, 4, 5]
#    [4, 5, 6]
#    [5, 6, 7]
#    [6, 7, 8]
#    [7, 8, 9]
#    [8, 9, 10]

[SEE_ALSO] Enumerable#each_slice

each_entry -> Enumerator[permalink][rdoc][edit]
each_entry {|obj| block} -> self

ブロックを各要素に一度ずつ適用します。

一要素として複数の値が渡された場合はブロックには配列として渡されます。



class Foo
  include Enumerable
  def each
    yield 1
    yield 1,2
  end
end
Foo.new.each_entry{|o| print o, " -- "}
# => 1 -- [1, 2] --

ブロックを省略した場合は Enumerator が返されます。

[SEE_ALSO] Enumerable#slice_before

each_slice(n) -> Enumerator[permalink][rdoc][edit]
each_slice(n) {|list| ... } -> self

n 要素ずつブロックに渡して繰り返します。

要素数が n で割り切れないときは、最後の回だけ要素数が減ります。

ブロックを省略した場合は n 要素ずつ繰り返す Enumerator を返します。

[PARAM] n:
区切る要素数を示す整数です。


(1..10).each_slice(3) {|a| p a}
    # => [1, 2, 3]
    #    [4, 5, 6]
    #    [7, 8, 9]
    #    [10]

[SEE_ALSO] Enumerable#each_cons

each_with_index(*args) -> Enumerator[permalink][rdoc][edit]
each_with_index(*args) {|item, index| ... } -> self

要素とそのインデックスをブロックに渡して繰り返します。

ブロックを省略した場合は、要素とそのインデックスを繰り返すような Enumerator を返します。

Enumerator#with_index は offset 引数を受け取りますが、 each_with_index は受け取りません (引数はイテレータメソッドにそのまま渡されます)。

[PARAM] args:
イテレータメソッド (each など) にそのまま渡されます。


[5, 10, 15].each_with_index do |n, idx|
  p [n, idx]
end
# => [5, 0]
#    [10, 1]
#    [15, 2]
引数ありの例

require 'stringio'
StringIO.new("foo|bar|baz").each_with_index("|") do |s, i|
  p [s, i]
end
# => ["foo|", 0]
#    ["bar|", 1]
#    ["baz", 2]

[SEE_ALSO] Enumerator#with_index

each_with_object(obj) -> Enumerator[permalink][rdoc][edit]
each_with_object(obj) {|(*args), memo_obj| ... } -> object

与えられた任意のオブジェクトと要素をブロックに渡し繰り返し、最初に与えられたオブジェクトを返します。

ブロックを省略した場合は Enumerator を返します。

[PARAM] obj:
任意のオブジェクトを指定します。


evens = (1..10).each_with_object([]) {|i, a| a << i*2 }
# => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

[SEE_ALSO] Enumerator#with_object

to_a(*args) -> [object][permalink][rdoc][edit]
entries(*args) -> [object]

全ての要素を含む配列を返します。

[PARAM] args:
each の呼び出し時に引数として渡されます。


(1..7).to_a                       #=> [1, 2, 3, 4, 5, 6, 7]
{ 'a'=>1, 'b'=>2, 'c'=>3 }.to_a   #=> [["a", 1], ["b", 2], ["c", 3]]

require 'prime'
Prime.entries 10                  #=> [2, 3, 5, 7]
find_all -> Enumerator[permalink][rdoc][edit]
select -> Enumerator
filter -> Enumerator
find_all {|item| ... } -> [object]
select {|item| ... } -> [object]
filter {|item| ... } -> [object]

各要素に対してブロックを評価した値が真であった要素を全て含む配列を返します。真になる要素がひとつもなかった場合は空の配列を返します。

ブロックを省略した場合は Enumerator を返します。



(1..10).find_all                        # => #<Enumerator: 1..10:find_all>
(1..10).find_all { |i| i % 3 == 0 }     # => [3, 6, 9]

[1,2,3,4,5].select                      # => #<Enumerator: [1, 2, 3, 4, 5]:select>
[1,2,3,4,5].select { |num| num.even? }  # => [2, 4]

[SEE_ALSO] Enumerable#reject

[SEE_ALSO] Enumerable#grep

filter_map {|item| ... } -> [object][permalink][rdoc][edit]
filter_map -> Enumerator

各要素に対してブロックを評価した値のうち、真であった値の配列を返します。

ブロックを省略した場合は Enumerator を返します。



(1..10).filter_map { |i| i * 2 if i.even? } #=> [4, 8, 12, 16, 20]

[SEE_ALSO] Enumerable#filter, Enumerable#map

find_index(val) -> Integer | nil[permalink][rdoc][edit]
find_index {|obj| ... } -> Integer | nil
find_index -> Enumerator

条件に一致する最初の要素の位置を返します。

[PARAM] val:
位置を知りたいオブジェクトを指定します。

指定された val と == で等しい最初の要素の位置を返します。等しい要素がひとつもなかった場合は nil を返します。



(1..10).find_index(11)  #=> nil
(1..10).find_index(2)   #=> 1

ブロックが与えられた場合には、各要素を引数として先頭から順にブロックを実行し、ブロックが真を返した最初の要素の位置を返します。一つも真にならなかった場合は nil を返します。



(1..10).find_index  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
(1..100).find_index {|i| i % 5 == 0 and i % 7 == 0 }   #=> 34

引数、ブロックのどちらも与えられなかった場合は、 Enumerator のインスタンスを返します。

first -> object | nil[permalink][rdoc][edit]
first(n) -> Array

Enumerable オブジェクトの最初の要素、もしくは最初の n 要素を返します。

Enumerable オブジェクトが空の場合、引数を指定しない形式では nil を返します。引数を指定する形式では、空の配列を返します。

[PARAM] n:
取得する要素数。


e = "abcd".each_byte
e.first #=> 97
e.first(2) #=> [97,98]
e = "".each_byte
e.first #=> nil
e.first(2) #=> []
grep(pattern) -> [object][permalink][rdoc][edit]
grep(pattern) {|item| ... } -> [object]

pattern === item が成立する要素を全て含んだ配列を返します。

ブロックとともに呼び出された時には条件の成立した要素に対してそれぞれブロックを評価し、その結果の配列を返します。マッチする要素がひとつもなかった場合は空の配列を返します。

[PARAM] pattern:
「===」メソッドを持つオブジェクトを指定します。


['aa', 'bb', 'cc', 'dd', 'ee'].grep(/[bc]/)  # => ["bb", "cc"]

  Array.instance_methods.grep(/gr/) # => [:grep, :group_by]

[SEE_ALSO] Enumerable#select

[SEE_ALSO] Enumerable#grep_v

grep_v(pattern) -> [object][permalink][rdoc][edit]
grep_v(pattern) { |item| ... } -> [object]

Enumerable#grep のマッチの条件を逆にして、pattern === item が成立しない要素を全て含んだ配列を返します。

[PARAM] pattern:
「===」メソッドを持つオブジェクトを指定します。


(1..10).grep_v 2..5   # => [1, 6, 7, 8, 9, 10]
res =(1..10).grep_v(2..5) { |v| v * 2 }
res                   # => [2, 12, 14, 16, 18, 20]

[SEE_ALSO] Enumerable#grep

[SEE_ALSO] Enumerable#reject

group_by -> Enumerator[permalink][rdoc][edit]
group_by {|obj| ... } -> Hash

ブロックを評価した結果をキー、対応する要素の配列を値とするハッシュを返します。



(1..6).group_by {|i| i%3}   #=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}

ブロックを省略した場合は Enumerator を返します。

member?(val) -> bool[permalink][rdoc][edit]
include?(val) -> bool

val と == の関係にある要素を含むとき真を返します。

[PARAM] val:
任意のオブジェクト


[2, 4, 6].include? 2 #=> true
[2, 4, 6].include? 1 #=> false
[2, 4, 6].member? 2  #=> true
[2, 4, 6].member? 1  #=> false
inject(init = self.first) {|result, item| ... } -> object[permalink][rdoc][edit]
inject(sym) -> object
inject(init, sym) -> object
reduce(init = self.first) {|result, item| ... } -> object
reduce(sym) -> object
reduce(init, sym) -> object

リストのたたみこみ演算を行います。

最初に初期値 init と self の最初の要素を引数にブロックを実行します。 2 回目以降のループでは、前のブロックの実行結果と self の次の要素を引数に順次ブロックを実行します。そうして最後の要素まで繰り返し、最後のブロックの実行結果を返します。

要素が存在しない場合は init を返します。

初期値 init を省略した場合は、最初に先頭の要素と 2 番目の要素をブロックに渡します。また要素が 1 つしかなければブロックを実行せずに最初の要素を返します。要素がなければブロックを実行せずに nil を返します。

[PARAM] init:
最初の result の値です。任意のオブジェクトが渡せます。
[PARAM] sym:
ブロックの代わりに使われるメソッド名を表す Symbol オブジェクトを指定します。実行結果に対して sym という名前のメソッドが呼ばれます。


# 合計を計算する。
p [2, 3, 4, 5].inject {|result, item| result + item }        #=> 14

# 自乗和を計算する。初期値をセットする必要がある。
p [2, 3, 4, 5].inject(0) {|result, item| result + item**2 }  #=> 54

この式は以下のように書いても同じ結果が得られます。



result = 0
[1, 2, 3, 4, 5].each {|v| result += v }
p result   # => 15

p [1, 2, 3, 4, 5].inject(:+)                    #=> 15
p ["b", "c", "d"].inject("abbccddde", :squeeze) #=> "abcde"
lazy -> Enumerator::Lazy[permalink][rdoc][edit]

自身を lazy な Enumerator に変換したものを返します。

この Enumerator は、以下のメソッドが遅延評価を行う (つまり、配列ではなくEnumeratorを返す) ように再定義されています。

  • map/collect
  • flat_map/collect_concat
  • select/find_all
  • reject
  • grep
  • take, take_while
  • drop, drop_while
  • zip (※一貫性のため、ブロックを渡さないケースのみlazy)
  • cycle (※一貫性のため、ブロックを渡さないケースのみlazy)

以下はピタゴラス数 (a**2 + b**2 = c**2 を満たす自然数 a, b, c の組) を列挙するプログラムです。



def pythagorean_triples
  (1..Float::INFINITY).lazy.flat_map {|z|
    (1..z).flat_map {|x|
      (x..z).select {|y|
        x**2 + y**2 == z**2
      }.map {|y|
        [x, y, z]
      }
    }
  }
end
# 最初の10個のピタゴラス数を表示する
p pythagorean_triples.take(10).force # takeはlazyなので、forceが必要です
p pythagorean_triples.first(10)      # firstはeagerです
# 100より小さいピタゴラス数を表示する
p pythagorean_triples.take_while { |*, z| z < 100 }.force

[SEE_ALSO] Enumerator::Lazy

max -> object | nil[permalink][rdoc][edit]
max(n) -> Array

最大の要素、もしくは最大の n 要素が入った降順の配列を返します。全要素が互いに <=> メソッドで比較できることを仮定しています。

引数を指定しない形式では要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。該当する要素が複数存在する場合、どの要素を返すかは不定です。

[PARAM] n:
取得する要素数。


a = %w(albatross dog horse)
a.max                        # => "horse"
a.max(2)                     # => ["horse", "dog"]
max {|a, b| ... } -> object | nil[permalink][rdoc][edit]
max(n) {|a, b| ... } -> Array

ブロックの評価結果で各要素の大小判定を行い、最大の要素、もしくは最大の n 要素が入った降順の配列を返します。引数を指定しない形式では要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。

ブロックの値は、a > b のとき正、 a == b のとき 0、a < b のとき負の整数を、期待しています。

該当する要素が複数存在する場合、どの要素を返すかは不定です。

[PARAM] n:
取得する要素数。
[EXCEPTION] TypeError:
ブロックが整数以外を返したときに発生します。


class Person
  attr_reader :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end
end

people = [
  Person.new("sato", 55),
  Person.new("sato", 33),
  Person.new("sato", 11),
  Person.new("suzuki", 55),
  Person.new("suzuki", 33),
  Person.new("suzuki", 11),
  Person.new("tanaka", 55),
  Person.new("tanaka", 33),
  Person.new("tanaka", 11)
]

# 年齢が最大、名前が最小
people.max { |x, y| (x.age <=> y.age).nonzero? || y.name <=> x.name }
# => #<Person:0x007fc54b0240a0 @name="sato", @age=55>
people.max(2) { |x, y| (x.age <=> y.age).nonzero? || y.name <=> x.name }
# => [#<Person:0x007fc54b0240a0 @name="sato", @age=55>, #<Person:0x007fc54c033ea0 @name="suzuki", @age=55>]
max_by -> Enumerator[permalink][rdoc][edit]
max_by(n) -> Enumerator
max_by {|item| ... } -> object | nil
max_by(n) {|item| ... } -> Array

各要素を順番にブロックに渡して実行し、その評価結果を <=> で比較して、最大であった値に対応する元の要素、もしくは最大の n 要素が降順で入った配列を返します。

引数を指定しない形式では要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。該当する要素が複数存在する場合、どの要素を返すかは不定です。

Enumerable#maxEnumerable#max_by の違いは Enumerable#sortEnumerable#sort_by の違いと同じです。

ブロックを省略した場合は Enumerator を返します。

[PARAM] n:
取得する要素数。


a = %w(albatross dog horse)
a.max_by                    # => #<Enumerator: ["albatross", "dog", "horse"]:max_by>
a.max_by { |x| x.length }   # => "albatross"


a = %w[albatross dog horse]
a.max_by(2)                 # => #<Enumerator: ["albatross", "dog", "horse"]:max_by(2)>
a.max_by(2) {|x| x.length } # => ["albatross", "horse"]
例: enum.max_by(n)は、重み付きランダムサンプリングを実装するために使用できます。次の実装例は、Enumerable#wsampleを使用します。

module Enumerable
  # weighted random sampling.
  #
  # Pavlos S. Efraimidis, Paul G. Spirakis
  # Weighted random sampling with a reservoir
  # Information Processing Letters
  # Volume 97, Issue 5 (16 March 2006)
  def wsample(n)
    self.max_by(n) {|v| rand ** (1.0/yield(v)) }
  end
end
e = (-20..20).to_a*10000
a = e.wsample(20000) {|x|
  Math.exp(-(x/5.0)**2) # normal distribution
}
# a is 20000 samples from e.
p a.length #=> 20000
h = a.group_by {|x| x }
-10.upto(10) {|x| puts "*" * (h[x].length/30.0).to_i if h[x] }
#=> *
#   ***
#   ******
#   ***********
#   ******************
#   *****************************
#   *****************************************
#   ****************************************************
#   ***************************************************************
#   ********************************************************************
#   ***********************************************************************
#   ***********************************************************************
#   **************************************************************
#   ****************************************************
#   ***************************************
#   ***************************
#   ******************
#   ***********
#   *******
#   ***
#   *

[SEE_ALSO] Enumerable#sort_by

min -> object | nil[permalink][rdoc][edit]
min(n) -> Array

最小の要素、もしくは最小の n 要素が昇順で入った配列を返します。全要素が互いに <=> メソッドで比較できることを仮定しています。

引数を指定しない形式では要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。該当する要素が複数存在する場合、どの要素を返すかは不定です。

[PARAM] n:
取得する要素数。


a = %w(albatross dog horse)
a.min                                # => "albatross"
a.min(2)                             # => ["albatross", "dog"]
min {|a, b| ... } -> object | nil[permalink][rdoc][edit]
min(n) {|a, b| ... } -> Array

ブロックの評価結果で各要素の大小判定を行い、最小の要素、もしくは最小の n 要素が昇順で入った配列を返します。引数を指定しない形式では要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。

ブロックの値は、a > b のとき正、a == b のとき 0、 a < b のとき負の整数を、期待しています。

該当する要素が複数存在する場合、どの要素を返すかは不定です。

[PARAM] n:
取得する要素数。


class Person
  attr_reader :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end
end

people = [
  Person.new("sato", 55),
  Person.new("sato", 33),
  Person.new("sato", 11),
  Person.new("suzuki", 55),
  Person.new("suzuki", 33),
  Person.new("suzuki", 11),
  Person.new("tanaka", 55),
  Person.new("tanaka", 33),
  Person.new("tanaka", 11)
]

# 年齢が最小、名前が最大
people.min { |x, y| (x.age <=> y.age).nonzero? || y.name <=> x.name }
# => #<Person:0x007fd6f0824190 @name="tanaka", @age=11>

people.min(2) { |x, y| (x.age <=> y.age).nonzero? || y.name <=> x.name }
# => [#<Person:0x007fb5899ef4a8 @name="tanaka", @age=11>, #<Person:0x007fb5899ef728 @name="suzuki", @age=11>]
[EXCEPTION] TypeError:
ブロックが整数以外を返したときに発生します。
min_by -> Enumerator[permalink][rdoc][edit]
min_by(n) -> Enumerator
min_by {|item| ... } -> object | nil
min_by(n) {|item| ... } -> Array

各要素を順番にブロックに渡して評価し、その評価結果を <=> で比較して、最小であった値に対応する元の要素、もしくは最小の n 要素が昇順で入った配列を返します。

引数を指定しない形式では要素が存在しなければ nil を返します。引数を指定する形式では、空の配列を返します。

該当する要素が複数存在する場合、どの要素を返すかは不定です。

ブロックを省略した場合は Enumerator を返します。

Enumerable#minEnumerable#min_by の違いは Enumerable#sortEnumerable#sort_by の違いと同じです。

[PARAM] n:
取得する要素数。


a = %w(albatross dog horse)
a.min_by                    # => #<Enumerator: ["albatross", "dog", "horse"]:min_by>
a.min_by { |x| x.length }   # => "dog"
a.min_by(2)                 # => #<Enumerator: ["albatross", "dog", "horse"]:min_by(2)>
a.min_by(2) {|x| x.length } # => ["dog", "horse"]

[SEE_ALSO] Enumerable#sort_by

minmax -> [object, object][permalink][rdoc][edit]
minmax {|a, b| ... } -> [object, object]

Enumerable オブジェクトの各要素のうち最小の要素と最大の要素を要素とするサイズ 2 の配列を返します。

該当する要素が複数存在する場合、どの要素を返すかは不定です。

一つ目の形式は、Enumerable オブジェクトのすべての要素が Comparable を実装していることを仮定しています。二つ目の形式では、要素同士の比較をブロックを用いて行います。



a = %w(albatross dog horse)
a.minmax                                 #=> ["albatross", "horse"]
a.minmax{|a,b| a.length <=> b.length }   #=> ["dog", "albatross"]
[].minmax # => [nil, nil]

[SEE_ALSO] Enumerable#sort, Array#minmax

minmax_by -> Enumerator[permalink][rdoc][edit]
minmax_by {|obj| ... } -> [object, object]

Enumerable オブジェクトの各要素をブロックに渡して評価し、その結果を <=> で比較して最小の要素と最大の要素を要素とするサイズ 2 の配列を返します。

該当する要素が複数存在する場合、どの要素を返すかは不定です。

Enumerable#minmaxEnumerable#minmax_by の違いは sort と sort_by の違いと同じです。詳細は Enumerable#sort_by を参照してください。



a = %w(albatross dog horse)
a.minmax_by {|x| x.length }   #=> ["dog", "albatross"]

[].minmax_by{} # => [nil, nil]

ブロックを省略した場合は Enumerator を返します。

[SEE_ALSO] Enumerable#sort_by

none? -> bool[permalink][rdoc][edit]
none? {|obj| ... } -> bool
none?(pattern) -> bool

ブロックを指定しない場合は、 Enumerable オブジェクトのすべての要素が偽であれば真を返します。そうでなければ偽を返します。

ブロックを指定した場合は、Enumerable オブジェクトのすべての要素をブロックで評価した結果が、すべて偽であれば真を返します。そうでなければ偽を返します。

自身に要素が存在しない場合は true を返します。

[PARAM] pattern:
ブロックの代わりに各要素に対して pattern === item を評価します。


require 'set'
Set['ant', 'bear', 'cat'].none? {|word| word.length == 5}  # => true
Set['ant', 'bear', 'cat'].none? {|word| word.length >= 4}  # => false
Set['ant', 'bear', 'cat'].none?(/d/)                       # => true
Set[].none?                                                # => true
Set[nil].none?                                             # => true
Set[nil,false].none?                                       # => true
Set[nil, false, true].none?                                # => false

[SEE_ALSO] Array#none?

one? -> bool[permalink][rdoc][edit]
one? {|obj| ... } -> bool
one?(pattern) -> bool

ブロックを指定しない場合は、 Enumerable オブジェクトの要素のうちちょうど一つだけが真であれば、真を返します。そうでなければ偽を返します。

ブロックを指定した場合は、Enumerable オブジェクトの要素をブロックで評価した結果、一つの要素だけが真であれば真を返します。そうでなければ偽を返します。

[PARAM] pattern:
ブロックの代わりに各要素に対して pattern === item を評価します。


require 'set'
Set['ant', 'bear', 'cat'].one? {|word| word.length == 4}  # => true
Set['ant', 'bear', 'cat'].one? {|word| word.length > 4}   # => false
Set['ant', 'bear', 'cat'].one?(/t/)                       # => false
Set[nil, true, 99].one?                                   # => false
Set[nil, true, false].one?                                # => true
Set[nil, true, 99].one?(Integer)                          # => true
Set[].one?                                                # => false

[SEE_ALSO] Array#one?

partition -> Enumerator[permalink][rdoc][edit]
partition {|item| ... } -> [[object], [object]]

各要素を、ブロックの条件を満たす要素と満たさない要素に分割します。各要素に対してブロックを評価して、その値が真であった要素の配列と、偽であった要素の配列の 2 つを配列に入れて返します。

ブロックを省略した場合は Enumerator を返します。



[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0].partition {|i| i % 3 == 0 }
 #=> [[9, 6, 3, 0], [10, 8, 7, 5, 4, 2, 1]]
reject -> Enumerator[permalink][rdoc][edit]
reject {|item| ... } -> [object]

各要素に対してブロックを評価し、その値が偽であった要素を集めた新しい配列を返します。条件を反転させた select です。

ブロックを省略した場合は Enumerator を返します。



# 偶数を除外する (奇数を集める)
(1..6).reject {|i| i % 2 == 0 } # => [1, 3, 5]

[SEE_ALSO] Enumerable#select, Array#reject

[SEE_ALSO] Enumerable#grep_v

reverse_each -> Enumerator[permalink][rdoc][edit]
reverse_each {|element| ... } -> self

逆順に各要素に対してブロックを評価します。

内部で各要素を保持した配列を作ります。

ブロックを省略した場合は、各要素を逆順に辿る Enumerator を返します。



{a: 1, b: 2, c: 3}.reverse_each # => #<Enumerator: ...>
{a: 1, b: 2, c: 3}.reverse_each { |v| p v }
# => [:c, 3]
#    [:b, 2]
#    [:a, 1]
slice_after(pattern) -> Enumerator[permalink][rdoc][edit]
slice_after {|elt| bool } -> Enumerator

パターンがマッチした要素、もしくはブロックが真を返した要素を末尾の要素としてチャンク化(グループ化)したものを繰り返す Enumerator を 返します。

パターンを渡した場合は各要素に対し === が呼び出され、 それが真になったところをチャンクの末尾と見なします。 ブロックを渡した場合は、各要素に対しブロックを適用し 返り値が真であった要素をチャンクの末尾と見なします。

パターンもブロックも最初から最後の要素まで呼び出されます。

各チャンクは配列として表現されます。そのため、以下のような呼び出しを行う事もできます。



enum.slice_after(pattern).each { |ary|
  # ...
}
enum.slice_after { |elt| bool }.each { |ary|
  # ...
}


# 偶数要素をチャンクの末尾と見なす
[0,2,4,1,2,4,5,3,1,4,2].slice_after(&:even?).to_a
# => [[0], [2], [4], [1, 2], [4], [5, 3, 1, 4], [2]]

# 奇数要素をチャンクの末尾と見なす
[0,2,4,1,2,4,5,3,1,4,2].slice_after(&:odd?).to_a
# => [[0, 2, 4, 1], [2, 4, 5], [3], [1], [4, 2]]

# バックスラッシュで終わる行を継続
lines = ["foo\n", "bar\\\n", "baz\n", "\n", "qux\n"]
e = lines.slice_after(/(?<!\\)\n\z/)
p e.to_a
#=> [["foo\n"], ["bar\\\n", "baz\n"], ["\n"], ["qux\n"]]
p e.map {|ll| ll[0...-1].map {|l| l.sub(/\\\n\z/, "") }.join + ll.last }
#=>["foo\n", "barbaz\n", "\n", "qux\n"]

Enumerable#map のようなメソッドを使うこともできます。

[SEE_ALSO] Enumerable#chunk, Enumerable#slice_before

slice_before(pattern) -> Enumerator[permalink][rdoc][edit]
slice_before {|elt| bool } -> Enumerator

パターンがマッチした要素、もしくはブロックが真を返した要素から次にマッチする手前までをチャンク化(グループ化)したものを繰り返す Enumerator を返します。

パターンを渡した場合は各要素に対し === が呼び出され、それが真になったところをチャンクの先頭と見なします。ブロックを渡した場合は、各要素に対しブロックを適用し返り値が真であった要素をチャンクの先頭と見なします。

より厳密にいうと、「先頭要素」の手前で分割していきます。最初の要素の評価は無視されます。

各チャンクは配列として表現されます。

Enumerable#to_aEnumerable#map のようなメソッドを使うこともできます。



# 偶数要素をチャンクの先頭と見なす
[0,2,4,1,2,4,5,3,1,4,2].slice_before(&:even?).to_a
# => [[0], [2], [4, 1], [2], [4, 5, 3, 1], [4], [2]]

# 奇数要素をチャンクの先頭と見なす
[0,2,4,1,2,4,5,3,1,4,2].slice_before(&:odd?).to_a
# => [[0, 2, 4], [1, 2, 4], [5], [3], [1, 4, 2]]

# ChangeLog のエントリーを順に取る
open("ChangeLog") {|f|
  f.slice_before(/\A\S/).each {|e| pp e}
}

# 上と同じだが、パターンでなくブロックを使う
open("ChangeLog") {|f|
  f.slice_before {|line| /\A\S/ === line }.each {|e| pp e}
}

# "svn proplist -R" の結果を分割する
# これは一要素が複数行にまたがっている

IO.popen([{"LC_ALL"=>"C"}, "svn", "proplist", "-R"]) {|f|
  f.lines.slice_before(/\AProp/).each {|lines| p lines }
}
#=> ["Properties on '.':\n", "  svn:ignore\n", "  svk:merge\n"]
#   ["Properties on 'goruby.c':\n", "  svn:eol-style\n"]
#   ["Properties on 'complex.c':\n", "  svn:mime-type\n", "  svn:eol-style\n"]
#   ["Properties on 'regparse.c':\n", "  svn:eol-style\n"]
#   ...

複数要素にわたる状態遷移が必要な場合は、ローカル変数でこれを実現することができます。例えば、連続に増える数値が3つ以上ある場合、これをまとめる処理をするためには以下のようにします (Enumerable#chunk_while のより簡単な例も参照)。


a = [0,2,3,4,6,7,9]
prev = a[0]
p a.slice_before {|e|
  prev, prev2 = e, prev
  prev2 + 1 != e
}.map {|es|
  es.length <= 2 ? es.join(",") : "#{es.first}-#{es.last}"
}.join(",")
#=> "0,2-4,6,7,9"

[SEE_ALSO] Enumerable#chunk, Enumerable#slice_after

slice_when {|elt_before, elt_after| bool } -> Enumerator[permalink][rdoc][edit]

要素を前から順にブロックで評価し、その結果によって要素をチャンクに分けた(グループ化した)要素を持つEnumerator を返します。

隣り合う値をブロックパラメータ elt_before、elt_after に渡し、ブロックの評価値が真になる所でチャンクを区切ります。

ブロックは self の長さ - 1 回呼び出されます。

[RETURN]
チャンクごとの配列をブロックパラメータに渡す Enumerator を返します。eachメソッドは以下のように呼び出します。
  enum.slice_when { |elt_before, elt_after| bool }.each { |ary| ... }
to_a や map などのその他の Enumerable モジュールのメソッドも有用です。


# 1ずつ増加する部分配列ごとに分ける。
a = [1,2,4,9,10,11,12,15,16,19,20,21]
b = a.slice_when {|i, j| i+1 != j }
p b.to_a # => [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
p c # => [[1, 2], [4], "9-12", [15, 16], "19-21"]
d = c.join(",")
p d # => "1,2,4,9-12,15,16,19-21"

# ソート済の配列を近い値(差が6以内)の部分配列ごとに分ける。
a = [3, 11, 14, 25, 28, 29, 29, 41, 55, 57]
p a.slice_when {|i, j| 6 < j - i }.to_a
# => [[3], [11, 14], [25, 28, 29, 29], [41], [55, 57]]

# 増加のみの部分配列ごとに分ける。
a = [0, 9, 2, 2, 3, 2, 7, 5, 9, 5]
p a.slice_when {|i, j| i > j }.to_a
# => [[0, 9], [2, 2, 3], [2, 7], [5, 9], [5]]

# 隣り合う偶数同士、奇数同士の部分配列ごとに分ける。
# (Enumerable#chunk を使って実現する事も可能)
a = [7, 5, 9, 2, 0, 7, 9, 4, 2, 0]
p a.slice_when {|i, j| i.even? != j.even? }.to_a
# => [[7, 5, 9], [2, 0], [7, 9], [4, 2, 0]]

# 段落(空行が後ろに続く非空行の文字列)ごとに分ける。
# (Enumerable#chunk で空行を無視して実現する事も可能)
lines = ["foo\n", "bar\n", "\n", "baz\n", "qux\n"]
p lines.slice_when {|l1, l2| /\A\s*\z/ =~ l1 && /\S/ =~ l2 }.to_a
# => [["foo\n", "bar\n", "\n"], ["baz\n", "qux\n"]]

Enumerable#chunk_while はブロックの戻り値が偽ではなく真の時に要素を分ける事を除いて同じ処理を行います。

[SEE_ALSO] Enumerable#chunk_while, Enumerable#chunk

sort -> [object][permalink][rdoc][edit]
sort {|a, b| ... } -> [object]

全ての要素を昇順にソートした配列を生成して返します。

ブロックなしのときは <=> メソッドを要素に対して呼び、その結果をもとにソートします。

<=> 以外でソートしたい場合は、ブロックを指定します。この場合、ブロックの評価結果を元にソートします。ブロックの値は、a > b のとき正、a == b のとき 0、 a < b のとき負の整数を、期待しています。ブロックが整数以外を返したときは例外 TypeError が発生します。

Enumerable#sort は安定ではありません (unstable sort)。安定なソートが必要な場合は Enumerable#sort_by を使って工夫する必要があります。詳しくは Enumerable#sort_by の項目を参照してください。

※ 比較結果が同じ要素は元の順序通りに並ぶソートを「安定なソート (stable sort)」と言います。



%w(rhea kea flea).sort           # => ["flea", "kea", "rhea"]
(1..10).sort { |a, b| b <=> a }  # => [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

[SEE_ALSO] Enumerable#sort_by

sort_by -> Enumerator[permalink][rdoc][edit]
sort_by {|item| ... } -> [object]

ブロックの評価結果を <=> メソッドで比較することで、self を昇順にソートします。ソートされた配列を新たに生成して返します。

つまり、以下とほぼ同じ動作をします。



class Array
  def sort_by
    self.map {|i| [yield(i), i] }.
       sort {|a, b| a[0] <=> b[0] }.
       map {|i| i[1]}
  end
end

Enumerable#sort と比較して sort_by が優れている点として、比較条件が複雑な場合の速度が挙げられます。 sort_by を使わない以下の例では比較を行う度に downcase が実行されます。従って downcase の実行速度が遅ければ sort の速度が致命的に低下します。


p ["BAR", "FOO", "bar", "foo"].sort {|a, b| a.downcase <=> b.downcase }

一方、次のように sort_by を使うと downcase の実行回数は要素数と同じです。つまり、その部分の実行時間は O(n) のオーダーです。


p ["BAR", "FOO", "bar", "foo"].sort_by {|v| v.downcase }

以下の、実行回数の検証結果を参照してみてください。


class Integer
  def count
    $n += 1
    self
  end
end

ary = []
1.upto(1000) {|v| ary << rand(v) }

$n = 0
ary.sort {|a,b| a.count <=> b.count }
p $n          # => 18200

$n = 0
ary.sort_by {|v| v.count }
p $n          # => 1000

Enumerable#sort_by は安定ではありません (unstable sort)。ただし、sort_by を以下のように使うと安定なソートを実装できます。


i = 0
ary.sort_by {|v| [v, i += 1] }

※ 比較結果が同じ要素は元の順序通りに並ぶソートを「安定なソート (stable sort)」と言います。

ブロックを省略した場合は Enumerator を返します。

[SEE_ALSO] Enumerable#sort

sum(init=0) -> object[permalink][rdoc][edit]
sum(init=0) {|e| expr } -> object

要素の合計を返します。

ブロックが与えられた場合、加算する前に各要素にブロックが適用されます。

selfが空の場合、initを返します。



{ 1 => 10, 2 => 20 }.sum {|k, v| k * v }  # => 50
(1..10).sum                               # => 55
(1..10).sum {|v| v * 2 }                  # => 110
('a'..'z').sum                            # => TypeError

init 引数を明示的に指名すると数値以外のオブジェクトにも使えます。



{ 1 => 10, 2 => 20 }.sum([])                   #=> [1, 10, 2, 20]
"a\nb\nc".each_line.lazy.map(&:chomp).sum("")  #=> "abc"
[[1], [[2]], [3]].sum([])          #=> [1, [2], 3]

"+" メソッドが再定義されている場合、Enumerable#sum は再定義を無視することがあります(例えばInteger#+)。

[SEE_ALSO] Array#sum

take(n) -> Array[permalink][rdoc][edit]

Enumerable オブジェクトの先頭から n 要素を配列として返します。

[PARAM] n:
要素数を指定します。


e = [1, 2, 3, 4, 5, 0].each
e.take(3)             # => [1, 2, 3]

[SEE_ALSO] Array#take

take_while -> Enumerator[permalink][rdoc][edit]
take_while {|element| ... } -> Array

Enumerable オブジェクトの要素を順に偽になるまでブロックで評価します。最初に偽になった要素の手前の要素までを配列として返します。



e = [1, 2, 3, 4, 5, 0].each
e.take_while {|i| i < 3 }   # => [1, 2]

ブロックを省略した場合は Enumerator を返します。

[SEE_ALSO] Array#take_while

tally -> Hash[permalink][rdoc][edit]
tally(hash) -> Hash

self に含まれる要素を数え上げた結果を Hash で返します。 Hash のキーは self に含まれる要素で、Hash の値は対応する要素が出現する回数です。

返り値は Hash であり、内部でも Hash と同等に要素を区別し数えます。そのため、独自で定義するクラスでも Object#hashObject#eql? を適切に定義することで数えることができます。

[PARAM] hash:
結果を加算していく Hash を指定します。更新される値は Integer である必要があります。


["a", "b", "c", "b"].tally  #=> {"a"=>1, "b"=>2, "c"=>1}

h = {}
[:a, :b, :c].tally(h)
[:a, :b, :d].tally(h)

p h # => {:a=>2, :b=>2, :c=>1, :d=>1}
to_h(*args) -> Hash[permalink][rdoc][edit]
to_h(*args) { ... } -> Hash

self を [key, value] のペアの配列として解析した結果を Hash にして返します。

[PARAM] args:
each の呼び出し時に引数として渡されます。


%i[hello world].each_with_index.to_h # => {:hello => 0, :world => 1}

ブロックを指定すると各要素でブロックを呼び出し、その結果をペアとして使います。

ブロック付きの例

(1..5).to_h {|x| [x, x ** 2]} # => {1=>1, 2=>4, 3=>9, 4=>16, 5=>25}
uniq -> Array[permalink][rdoc][edit]
uniq { |item| ... } -> Array

self から重複した値を取り除いた配列を返します。

ブロックが与えられた場合、ブロックが返した値が重複した要素を取り除いた配列を返します。



olympics = {
  1896 => 'Athens',
  1900 => 'Paris',
  1904 => 'Chicago',
  1906 => 'Athens',
  1908 => 'Rome',
}
olympics.uniq{|k,v| v} # => [[1896, "Athens"], [1900, "Paris"], [1904, "Chicago"], [1908, "Rome"]]

(1..100).uniq{|x| (x**2) % 10 } # => [1, 2, 3, 4, 5, 10]

[SEE_ALSO] Array#uniq

zip(*lists) -> [[object]][permalink][rdoc][edit]
zip(*lists) {|v1, v2, ...| ...} -> nil

self と引数に渡した配列の各要素からなる配列の配列を生成して返します。生成される配列の要素数は self の要素数と同じです。

ブロック付きで呼び出した場合は、 self と引数に渡した配列の各要素を順番にブロックに渡します。

[PARAM] lists:
配列を指定します。配列でない場合は to_ary メソッドにより配列に変換します。 to_ary メソッドが無い場合は each を試します。


p (1..3).zip([4,5,6], [7,8,9])
# => [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

p (1..2).zip([:a,:b,:c], [:A,:B,:C,:D])
# => [[1, :a, :A], [2, :b, :B]]

p (1..5).zip([:a,:b,:c], [:A,:B,:C,:D])
# => [[1, :a, :A], [2, :b, :B],
#     [3, :c, :C], [4, nil, :D], [5, nil, nil]]


p [1,2,3].zip([4,5,6], [7,8,9]) {|ary|
  p ary
}
# => [1, 4, 7]
#    [2, 5, 8]
#    [3, 6, 9]
#    nil