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
Enumeratorobject, which can be used as an ::Enumerable.
Instance Method Summary
-
#each {|elm| ... } ⇒ Object
Iterates over the block according to how this
Enumeratorwas 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
nilif 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. |
| #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. |
| #find | Passes each entry in enum to block. |
| #find_all | Alias for Enumerable#select. |
| #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 | Returns an array containing all elements of |
| #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 ::Enumerable. |
| #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 382
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]) == INFINITY)) {
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
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 521
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;
}
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 602
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 947
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 416
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 1089
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 820
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 763
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 894
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 866
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 969
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 1106
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 578
static VALUE
enumerator_with_index(int argc, VALUE *argv, VALUE obj)
{
VALUE memo;
rb_scan_args(argc, argv, "01", &memo);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enumerator_enum_size);
if (NIL_P(memo))
memo = INT2FIX(0);
else
memo = 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 646
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;
}