Class: Enumerator
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
::Enumerable
|
|
Inherits: | Object |
Defined in: | enumerator.c, enumerator.c |
Overview
A class which allows both internal and external iteration.
An Enumerator can be created by the following methods.
Most methods have two forms: a block form where the contents are evaluated for each item in the enumeration, and a non-block form which returns a new Enumerator
wrapping the iteration.
enumerator = %w(one two three).each
puts enumerator.class # => Enumerator
enumerator.each_with_object("foo") do |item, obj|
puts "#{obj}: #{item}"
end
# foo: one
# foo: two
# foo: three
enum_with_obj = enumerator.each_with_object("foo")
puts enum_with_obj.class # => Enumerator
enum_with_obj.each do |item, obj|
puts "#{obj}: #{item}"
end
# foo: one
# foo: two
# foo: three
This allows you to chain Enumerators together. For example, you can map a list’s elements to strings containing the index and the element as a string via:
puts %w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
# => ["0:foo", "1:bar", "2:baz"]
An Enumerator can also be used as an external iterator. For example, #next returns the next value of the iterator or raises ::StopIteration
if the Enumerator
is at the end.
e = [1,2,3].each # returns an enumerator object.
puts e.next # => 1
puts e.next # => 2
puts e.next # => 3
puts e.next # raises StopIteration
You can use this to implement an internal iterator as follows:
def ext_each(e)
while true
begin
vs = e.next_values
rescue StopIteration
return $!.result
end
y = yield(*vs)
e.feed y
end
end
o = Object.new
def o.each
puts yield
puts yield(1)
puts yield(1, 2)
3
end
# use o.each as an internal iterator directly.
puts o.each {|*x| puts x; [:b, *x] }
# => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
# convert o.each to an external iterator for
# implementing an internal iterator.
puts ext_each(o.to_enum) {|*x| puts x; [:b, *x] }
# => [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
Class Method Summary
-
.new(size = nil) {|yielder| ... }
constructor
Creates a new
Enumerator
object, which can be used as an::Enumerable
.
Instance Method Summary
-
#+(enum) ⇒ Enumerator
Returns an enumerator object generated from this enumerator and a given enumerable.
-
#each {|elm| ... } ⇒ Object
Iterates over the block according to how this
Enumerator
was constructed. -
#each_with_index {|(*args), idx| ... }
Same as #with_index(0), i.e. there is no starting offset.
-
#each_with_object(obj) {|(*args), obj| ... }
Alias for #with_object.
-
#feed(obj) ⇒ nil
Sets the value to be returned by the next yield inside
e
. -
#inspect ⇒ String
Creates a printable version of e.
-
#next ⇒ Object
Returns the next object in the enumerator, and move the internal position forward.
-
#next_values ⇒ Array
Returns the next object as an array in the enumerator, and move the internal position forward.
-
#peek ⇒ Object
Returns the next object in the enumerator, but doesn’t move the internal position forward.
-
#peek_values ⇒ Array
Returns the next object as an array, similar to #next_values, but doesn’t move the internal position forward.
-
#rewind ⇒ e
Rewinds the enumeration sequence to the beginning.
-
#size ⇒ Integer, ...
Returns the size of the enumerator, or
nil
if it can’t be calculated lazily. -
#with_index(offset = 0) {|(*args), idx| ... }
Iterates the given block for each element with an index, which starts from
offset
. -
#with_object(obj) {|(*args), obj| ... }
(also: #each_with_object)
Iterates the given block for each element with an arbitrary object,
obj
, and returnsobj
- #initialize_copy(orig) Internal use only
::Enumerable
- Included
#all? | Passes each element of the collection to the given block. |
#any? | Passes each element of the collection to the given block. |
#chain | Returns an enumerator object generated from this enumerator and given enumerables. |
#chunk | Enumerates over the items, chunking them together based on the return value of the block. |
#chunk_while | Creates an enumerator for each chunked elements. |
#collect | Alias for Enumerable#map. |
#collect_concat | Alias for Enumerable#flat_map. |
#count | Returns the number of items in |
#cycle | Calls block for each element of enum repeatedly n times or forever if none or |
#detect | Alias for Enumerable#find. |
#drop | Drops first n elements from enum, and returns rest elements in an array. |
#drop_while | Drops elements up to, but not including, the first element for which the block returns |
#each_cons | Iterates the given block for each array of consecutive <n> elements. |
#each_entry | Calls block once for each element in |
#each_slice | Iterates the given block for each slice of <n> elements. |
#each_with_index | Calls block with two arguments, the item and its index, for each item in enum. |
#each_with_object | Iterates the given block for each element with an arbitrary object given, and returns the initially given object. |
#entries | Alias for Enumerable#to_a. |
#filter | Returns an array containing all elements of |
#find | Passes each entry in enum to block. |
#find_all | Alias for Enumerable#filter. |
#find_index | Compares each entry in enum with value or passes to block. |
#first | Returns the first element, or the first |
#flat_map | Returns a new array with the concatenated results of running block once for every element in enum. |
#grep | Returns an array of every element in enum for which |
#grep_v | Inverted version of Enumerable#grep. |
#group_by | Groups the collection by result of the block. |
#include? | Alias for Enumerable#member?. |
#inject | Combines all elements of enum by applying a binary operation, specified by a block or a symbol that names a method or operator. |
#lazy | Returns a lazy enumerator, whose methods map/collect, flat_map/collect_concat, select/find_all, reject, grep, grep_v, zip, take, take_while, drop, and drop_while enumerate values only on an as-needed basis. |
#map | Returns a new array with the results of running block once for every element in enum. |
#max | Returns the object in enum with the maximum value. |
#max_by | Returns the object in enum that gives the maximum value from the given block. |
#member? | Returns |
#min | Returns the object in enum with the minimum value. |
#min_by | Returns the object in enum that gives the minimum value from the given block. |
#minmax | Returns a two element array which contains the minimum and the maximum value in the enumerable. |
#minmax_by | Returns a two element array containing the objects in enum that correspond to the minimum and maximum values respectively from the given block. |
#none? | Passes each element of the collection to the given block. |
#one? | Passes each element of the collection to the given block. |
#partition | Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest. |
#reduce | Alias for Enumerable#inject. |
#reject | Returns an array for all elements of |
#reverse_each | Builds a temporary array and traverses that array in reverse order. |
#select | Alias for Enumerable#filter. |
#slice_after | Creates an enumerator for each chunked elements. |
#slice_before | Creates an enumerator for each chunked elements. |
#slice_when | Creates an enumerator for each chunked elements. |
#sort | Returns an array containing the items in enum sorted. |
#sort_by | Sorts enum using a set of keys generated by mapping the values in enum through the given block. |
#sum | Returns the sum of elements in an |
#take | Returns first n elements from enum. |
#take_while | Passes elements to the block until the block returns |
#to_a | Returns an array containing the items in enum. |
#to_h | Returns the result of interpreting enum as a list of |
#uniq | Returns a new array by removing duplicate values in |
#zip | Takes one element from enum and merges corresponding elements from each args. |
Constructor Details
.new(size = nil) {|yielder| ... }
.new(obj, method = :each, *args)
Creates a new Enumerator
object, which can be used as an ::Enumerable
.
In the first form, iteration is defined by the given block, in which a “yielder” object, given as block parameter, can be used to yield a value by calling the yield
method (aliased as <<
):
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
The optional parameter can be used to specify how to calculate the size in a lazy fashion (see #size). It can either be a value or a callable object.
In the second, deprecated, form, a generated Enumerator
iterates over the given object using the given method with the given arguments passed.
Use of this form is discouraged. Use Object#enum_for or Object#to_enum instead.
e = Enumerator.new(ObjectSpace, :each_object)
#-> ObjectSpace.enum_for(:each_object)
e.select { |obj| obj.is_a?(Class) } #=> array of all classes
# File 'enumerator.c', line 404
static VALUE enumerator_initialize(int argc, VALUE *argv, VALUE obj) { VALUE recv, meth = sym_each; VALUE size = Qnil; if (rb_block_given_p()) { rb_check_arity(argc, 0, 1); recv = generator_init(generator_allocate(rb_cGenerator), rb_block_proc()); if (argc) { if (NIL_P(argv[0]) || rb_respond_to(argv[0], id_call) || (RB_TYPE_P(argv[0], T_FLOAT) && RFLOAT_VALUE(argv[0]) == HUGE_VAL)) { size = argv[0]; } else { size = rb_to_int(argv[0]); } argc = 0; } } else { rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); rb_warn("Enumerator.new without a block is deprecated; use Object#to_enum"); recv = *argv++; if (--argc) { meth = *argv++; --argc; } } return enumerator_init(obj, recv, meth, argc, argv, 0, size); }
Instance Method Details
#+(enum) ⇒ Enumerator
Returns an enumerator object generated from this enumerator and a given enumerable.
e = (1..3).each + [4, 5]
e.to_a #=> [1, 2, 3, 4, 5]
# File 'enumerator.c', line 2697
static VALUE enumerator_plus(VALUE obj, VALUE eobj) { VALUE enums = rb_ary_new_from_args(2, obj, eobj); return enum_chain_initialize(enum_chain_allocate(rb_cEnumChain), enums); }
Iterates over the block according to how this Enumerator
was constructed. If no block and no arguments are given, returns self.
Examples
"Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
obj = Object.new
def obj.each_arg(a, b=:b, *rest)
yield a
yield b
yield rest
:method_returned
end
enum = obj.to_enum :each_arg, :a, :x
enum.each.to_a #=> [:a, :x, []]
enum.each.equal?(enum) #=> true
enum.each { |elm| elm } #=> :method_returned
enum.each(:y, :z).to_a #=> [:a, :x, [:y, :z]]
enum.each(:y, :z).equal?(enum) #=> false
enum.each(:y, :z) { |elm| elm } #=> :method_returned
# File 'enumerator.c', line 543
static VALUE enumerator_each(int argc, VALUE *argv, VALUE obj) { if (argc > 0) { struct enumerator *e = enumerator_ptr(obj = rb_obj_dup(obj)); VALUE args = e->args; if (args) { #if SIZEOF_INT < SIZEOF_LONG /* check int range overflow */ rb_long2int(RARRAY_LEN(args) + argc); #endif args = rb_ary_dup(args); rb_ary_cat(args, argv, argc); } else { args = rb_ary_new4(argc, argv); } e->args = args; e->size = Qnil; e->size_fn = 0; } if (!rb_block_given_p()) return obj; return enumerator_block_call(obj, 0, obj); }
#each_with_index {|(*args), idx| ... }
#each_with_index
Same as #with_index(0), i.e. there is no starting offset.
If no block is given, a new Enumerator
is returned that includes the index.
# File 'enumerator.c', line 623
static VALUE enumerator_each_with_index(VALUE obj) { return enumerator_with_index(0, NULL, obj); }
#each_with_object(obj) {|(*args), obj| ... }
#each_with_object(obj)
#with_object(obj) {|(*args), obj| ... }
#with_object(obj)
Alias for #with_object.
#feed(obj) ⇒ nil
Sets the value to be returned by the next yield inside e
.
If the value is not set, the yield returns nil.
This value is cleared after being yielded.
# Array#map passes the array's elements to "yield" and collects the
# results of "yield" as an array.
# Following example shows that "next" returns the passed elements and
# values passed to "feed" are collected as an array which can be
# obtained by StopIteration#result.
e = [1,2,3].map
p e.next #=> 1
e.feed "a"
p e.next #=> 2
e.feed "b"
p e.next #=> 3
e.feed "c"
begin
e.next
rescue StopIteration
p $!.result #=> ["a", "b", "c"]
end
o = Object.new
def o.each
x = yield # (2) blocks
p x # (5) => "foo"
x = yield # (6) blocks
p x # (8) => nil
x = yield # (9) blocks
p x # not reached w/o another e.next
end
e = o.to_enum
e.next # (1)
e.feed "foo" # (3)
e.next # (4)
e.next # (7)
# (10)
# File 'enumerator.c', line 968
static VALUE enumerator_feed(VALUE obj, VALUE v) { struct enumerator *e = enumerator_ptr(obj); if (e->feedvalue != Qundef) { rb_raise(rb_eTypeError, "feed value already set"); } e->feedvalue = v; return Qnil; }
#initialize_copy(orig)
# File 'enumerator.c', line 438
static VALUE enumerator_init_copy(VALUE obj, VALUE orig) { struct enumerator *ptr0, *ptr1; if (!OBJ_INIT_COPY(obj, orig)) return obj; ptr0 = enumerator_ptr(orig); if (ptr0->fib) { /* Fibers cannot be copied */ rb_raise(rb_eTypeError, "can't copy execution context"); } TypedData_Get_Struct(obj, struct enumerator, &enumerator_data_type, ptr1); if (!ptr1) { rb_raise(rb_eArgError, "unallocated enumerator"); } ptr1->obj = ptr0->obj; ptr1->meth = ptr0->meth; ptr1->args = ptr0->args; ptr1->fib = 0; ptr1->lookahead = Qundef; ptr1->feedvalue = Qundef; ptr1->size = ptr0->size; ptr1->size_fn = ptr0->size_fn; return obj; }
#inspect ⇒ String
Creates a printable version of e.
# File 'enumerator.c', line 1139
static VALUE enumerator_inspect(VALUE obj) { return rb_exec_recursive(inspect_enumerator, obj, 0); }
#next ⇒ Object
Returns the next object in the enumerator, and move the internal position forward. When the position reached at the end, ::StopIteration
is raised.
Example
a = [1,2,3]
e = a.to_enum
p e.next #=> 1
p e.next #=> 2
p e.next #=> 3
p e.next #raises StopIteration
Note that enumeration sequence by next
does not affect other non-external enumeration methods, unless the underlying iteration methods itself has side-effect, e.g. IO#each_line.
# File 'enumerator.c', line 841
static VALUE enumerator_next(VALUE obj) { VALUE vs = enumerator_next_values(obj); return ary2sv(vs, 0); }
#next_values ⇒ Array
Returns the next object as an array in the enumerator, and move the internal position forward. When the position reached at the end, ::StopIteration
is raised.
This method can be used to distinguish yield
and yield nil
.
Example
o = Object.new
def o.each
yield
yield 1
yield 1, 2
yield nil
yield [1, 2]
end
e = o.to_enum
p e.next_values
p e.next_values
p e.next_values
p e.next_values
p e.next_values
e = o.to_enum
p e.next
p e.next
p e.next
p e.next
p e.next
## yield args next_values next
# yield [] nil
# yield 1 [1] 1
# yield 1, 2 [1, 2] [1, 2]
# yield nil [nil] nil
# yield [1, 2] [[1, 2]] [1, 2]
Note that next_values
does not affect other non-external enumeration methods unless underlying iteration method itself has side-effect, e.g. IO#each_line.
# File 'enumerator.c', line 784
static VALUE enumerator_next_values(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); VALUE vs; if (e->lookahead != Qundef) { vs = e->lookahead; e->lookahead = Qundef; return vs; } return get_next_values(obj, e); }
#peek ⇒ Object
Returns the next object in the enumerator, but doesn’t move the internal position forward. If the position is already at the end, ::StopIteration
is raised.
Example
a = [1,2,3]
e = a.to_enum
p e.next #=> 1
p e.peek #=> 2
p e.peek #=> 2
p e.peek #=> 2
p e.next #=> 2
p e.next #=> 3
p e.peek #raises StopIteration
# File 'enumerator.c', line 915
static VALUE enumerator_peek(VALUE obj) { VALUE vs = enumerator_peek_values(obj); return ary2sv(vs, 1); }
#peek_values ⇒ Array
Returns the next object as an array, similar to #next_values, but doesn’t move the internal position forward. If the position is already at the end, ::StopIteration
is raised.
Example
o = Object.new
def o.each
yield
yield 1
yield 1, 2
end
e = o.to_enum
p e.peek_values #=> []
e.next
p e.peek_values #=> [1]
p e.peek_values #=> [1]
e.next
p e.peek_values #=> [1, 2]
e.next
p e.peek_values # raises StopIteration
# File 'enumerator.c', line 887
static VALUE enumerator_peek_values_m(VALUE obj) { return rb_ary_dup(enumerator_peek_values(obj)); }
#rewind ⇒ e
Rewinds the enumeration sequence to the beginning.
If the enclosed object responds to a “rewind” method, it is called.
# File 'enumerator.c', line 990
static VALUE enumerator_rewind(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); rb_check_funcall(e->obj, id_rewind, 0, 0); e->fib = 0; e->dst = Qnil; e->lookahead = Qundef; e->feedvalue = Qundef; e->stop_exc = Qfalse; return obj; }
#size ⇒ Integer, ...
Returns the size of the enumerator, or nil
if it can’t be calculated lazily.
(1..100).to_a.permutation(4).size # => 94109400
loop.size # => Float::INFINITY
(1..100).drop_while.size # => nil
# File 'enumerator.c', line 1156
static VALUE enumerator_size(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); int argc = 0; const VALUE *argv = NULL; VALUE size; if (e->procs) { struct generator *g = generator_ptr(e->obj); VALUE receiver = rb_check_funcall(g->obj, id_size, 0, 0); long i = 0; for (i = 0; i < RARRAY_LEN(e->procs); i++) { VALUE proc = RARRAY_AREF(e->procs, i); struct proc_entry *entry = proc_entry_ptr(proc); lazyenum_size_func *size_fn = entry->fn->size; if (!size_fn) { return Qnil; } receiver = (*size_fn)(proc, receiver); } return receiver; } if (e->size_fn) { return (*e->size_fn)(e->obj, e->args, obj); } if (e->args) { argc = (int)RARRAY_LEN(e->args); argv = RARRAY_CONST_PTR(e->args); } size = rb_check_funcall(e->size, id_call, argc, argv); if (size != Qundef) return size; return e->size; }
#with_index(offset = 0) {|(*args), idx| ... }
#with_index(offset = 0)
Iterates the given block for each element with an index, which starts from offset
. If no block is given, returns a new Enumerator
that includes the index, starting from offset
offset
-
the starting index to use
# File 'enumerator.c', line 602
static VALUE enumerator_with_index(int argc, VALUE *argv, VALUE obj) { VALUE memo; rb_check_arity(argc, 0, 1); RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size); memo = (!argc || NIL_P(memo = argv[0])) ? INT2FIX(0) : rb_to_int(memo); return enumerator_block_call(obj, enumerator_with_index_i, (VALUE)MEMO_NEW(memo, 0, 0)); }
#each_with_object(obj) {|(*args), obj| ... }
#each_with_object(obj)
#with_object(obj) {|(*args), obj| ... }
#with_object(obj)
Also known as: #each_with_object
Iterates the given block for each element with an arbitrary object, obj
, and returns obj
If no block is given, returns a new Enumerator
.
Example
to_three = Enumerator.new do |y|
3.times do |x|
y << x
end
end
to_three_with_string = to_three.with_object("foo")
to_three_with_string.each do |x,string|
puts "#{string}: #{x}"
end
# => foo:0
# => foo:1
# => foo:2
# File 'enumerator.c', line 667
static VALUE enumerator_with_object(VALUE obj, VALUE memo) { RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enumerator_enum_size); enumerator_block_call(obj, enumerator_with_object_i, memo); return memo; }