Class: Enumerator::Lazy
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::Enumerator
|
|
Instance Chain:
self,
::Enumerator ,
::Enumerable
|
|
Inherits: |
Enumerator
|
Defined in: | enumerator.c, enumerator.c |
Overview
Lazy
is a special type of ::Enumerator
, that allows constructing chains of operations without evaluating them immediately, and evaluating values on as-needed basis. In order to do so it redefines most of ::Enumerable
methods so that they just construct another lazy enumerator.
Lazy
can be constructed from any ::Enumerable
with the Enumerable#lazy method.
lazy = (1..Float::INFINITY).lazy.select(&:odd?).drop(10).take_while { |i| i < 30 }
# => #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: #<Enumerator::Lazy: 1..Infinity>:select>:drop(10)>:take_while>
The real enumeration is performed when any non-redefined ::Enumerable
method is called, like Enumerable#first or Enumerable#to_a (the latter is aliased as #force for more semantic code):
lazy.first(2)
#=> [21, 23]
lazy.force
#=> [21, 23, 25, 27, 29]
Note that most ::Enumerable
methods that could be called with or without a block, on Lazy
will always require a block:
[1, 2, 3].map #=> #<Enumerator: [1, 2, 3]:map>
[1, 2, 3].lazy.map # ArgumentError: tried to call lazy map without a block
This class allows idiomatic calculations on long or infinite sequences, as well as chaining of calculations without constructing intermediate arrays.
Example for working with a slowly calculated sequence:
require 'open-uri'
# This will fetch all URLs before selecting
# necessary data
URLS.map { |u| JSON.parse(open(u).read) }
.select { |data| data.key?('stats') }
.first(5)
# This will fetch URLs one-by-one, only till
# there is enough data to satisfy the condition
URLS.lazy.map { |u| JSON.parse(open(u).read) }
.select { |data| data.key?('stats') }
.first(5)
Ending a chain with “.eager” generates a non-lazy enumerator, which is suitable for returning or passing to another method that expects a normal enumerator.
def active_items
groups
.lazy
.flat_map(&:items)
.reject(&:disabled)
.eager
end
# This works lazily; if a checked item is found, it stops
# iteration and does not look into remaining groups.
first_checked = active_items.find(&:checked)
# This returns an array of items like a normal enumerator does.
all_checked = active_items.select(&:checked)
Class Method Summary
-
.new(obj, size = nil) {|yielder, *values| ... }
constructor
Creates a new
Lazy
enumerator.
::Enumerator
- Inherited
.new | Creates a new |
.produce | Creates an infinite enumerator from any block, just called over and over. |
Instance Method Summary
-
#_enumerable_collect {|obj| ... } ⇒ Array
Alias for Enumerable#collect.
-
#_enumerable_collect_concat {|obj| ... } ⇒ Array
Alias for Enumerable#collect_concat.
-
#_enumerable_drop(n) ⇒ Array
Alias for Enumerable#drop.
-
#_enumerable_drop_while {|obj| ... } ⇒ Array
Alias for Enumerable#drop_while.
-
#_enumerable_filter {|obj| ... } ⇒ Array
Alias for Enumerable#filter.
-
#_enumerable_filter_map {|obj| ... } ⇒ Array
Alias for Enumerable#filter_map.
-
#_enumerable_find_all {|obj| ... } ⇒ Array
Alias for Enumerable#find_all.
-
#_enumerable_flat_map {|obj| ... } ⇒ Array
Alias for Enumerable#flat_map.
-
#_enumerable_grep(pattern) ⇒ Array
Alias for Enumerable#grep.
-
#_enumerable_grep_v(pattern) ⇒ Array
Alias for Enumerable#grep_v.
-
#_enumerable_map {|obj| ... } ⇒ Array
Alias for Enumerable#map.
-
#_enumerable_reject {|obj| ... } ⇒ Array
Alias for Enumerable#reject.
-
#_enumerable_select {|obj| ... } ⇒ Array
Alias for Enumerable#select.
-
#_enumerable_take(n) ⇒ Array
Alias for Enumerable#take.
-
#_enumerable_take_while {|obj| ... } ⇒ Array
Alias for Enumerable#take_while.
-
#_enumerable_uniq ⇒ Array
Alias for Enumerable#uniq.
-
#_enumerable_zip(arg, ...) ⇒ an_array_of_array
Alias for Enumerable#zip.
- #chunk(*args) (also: #slice_before, #slice_after, #slice_when, #chunk_while)
-
#chunk_while(*args)
Alias for #chunk.
- #collect
-
#collect_concat {|obj| ... } ⇒ Lazy
Alias for #flat_map.
- #drop(n)
- #drop_while
-
#eager ⇒ Enumerator
Returns a non-lazy
::Enumerator
converted from the lazy enumerator. -
#enum_for(method = :each, *args) ⇒ Lazy
Alias for #to_enum.
- #filter
- #filter_map
- #find_all
-
#flat_map {|obj| ... } ⇒ Lazy
(also: #collect_concat)
Returns a new lazy enumerator with the concatenated results of running
block
once for every element in the lazy enumerator. -
#force ⇒ Array
Alias for #to_a.
- #grep
- #grep_v
-
#lazy ⇒ Lazy
Returns self.
- #map
- #reject
- #select
-
#slice_after(*args)
Alias for #chunk.
-
#slice_before(*args)
Alias for #chunk.
-
#slice_when(*args)
Alias for #chunk.
- #take(n)
- #take_while
-
#to_a ⇒ Array
(also: #force)
Expands #lazy enumerator to an array.
-
#to_enum(method = :each, *args) ⇒ Lazy
(also: #enum_for)
Similar to Object#to_enum, except it returns a lazy enumerator.
- #uniq
-
#zip(arg, ...) ⇒ Lazy
Like Enumerable#zip, but chains operation to be lazy-evaluated.
-
#_enumerable_with_index(offset = 0) {|(*args), idx| ... }
private
Alias for #with_index.
::Enumerator
- Inherited
#+ | Returns an enumerator object generated from this enumerator and a given enumerable. |
#each | Iterates over the block according to how this |
#each_with_index | Same as #with_index(0), i.e. there is no starting offset. |
#each_with_object | Alias for #with_object. |
#feed | Sets the value to be returned by the next yield inside |
#inspect | Creates a printable version of e. |
#next | Returns the next object in the enumerator, and move the internal position forward. |
#next_values | Returns the next object as an array in the enumerator, and move the internal position forward. |
#peek | Returns the next object in the enumerator, but doesn’t move the internal position forward. |
#peek_values | Returns the next object as an array, similar to #next_values, but doesn’t move the internal position forward. |
#rewind | Rewinds the enumeration sequence to the beginning. |
#size | Returns the size of the enumerator, or |
#with_index | Iterates the given block for each element with an index, which starts from |
#with_object | Iterates the given block for each element with an arbitrary object, |
#initialize_copy |
::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 |
#filter_map | Returns a new array containing the truthy results (everything except |
#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 an |
#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 |
#tally | Tallies the collection, i.e., counts the occurrences of each element. |
#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(obj, size = nil) {|yielder, *values| ... }
Creates a new Lazy
enumerator. When the enumerator is actually enumerated (e.g. by calling #force), obj
will be enumerated and each value passed to the given block. The block can yield values back using yielder
. For example, to create a “filter+map” enumerator:
def filter_map(sequence)
Lazy.new(sequence) do |yielder, *values|
result = yield *values
yielder << result if result
end
end
filter_map(1..Float::INFINITY) {|i| i*i if i.even?}.first(5)
#=> [4, 16, 36, 64, 100]
# File 'enumerator.c', line 1756
static VALUE lazy_initialize(int argc, VALUE *argv, VALUE self) { VALUE obj, size = Qnil; VALUE generator; rb_check_arity(argc, 1, 2); if (!rb_block_given_p()) { rb_raise(rb_eArgError, "tried to call lazy new without a block"); } obj = argv[0]; if (argc > 1) { size = argv[1]; } generator = generator_allocate(rb_cGenerator); rb_block_call(generator, id_initialize, 0, 0, lazy_init_block_i, obj); enumerator_init(self, generator, sym_each, 0, 0, 0, size, 0); rb_ivar_set(self, id_receiver, obj); return self; }
Instance Method Details
#_enumerable_collect {|obj| ... } ⇒ Array
#_enumerable_collect ⇒ Enumerator
Alias for Enumerable#collect.
#_enumerable_collect_concat {|obj| ... } ⇒ Array
#_enumerable_collect_concat ⇒ Enumerator
Alias for Enumerable#collect_concat.
#_enumerable_drop(n) ⇒ Array
Alias for Enumerable#drop.
#_enumerable_drop_while {|obj| ... } ⇒ Array
#_enumerable_drop_while ⇒ Enumerator
Alias for Enumerable#drop_while.
#_enumerable_filter {|obj| ... } ⇒ Array
#_enumerable_filter ⇒ Enumerator
Alias for Enumerable#filter.
#_enumerable_filter_map {|obj| ... } ⇒ Array
#_enumerable_filter_map ⇒ Enumerator
Alias for Enumerable#filter_map.
#_enumerable_find_all {|obj| ... } ⇒ Array
#_enumerable_find_all ⇒ Enumerator
Alias for Enumerable#find_all.
#_enumerable_flat_map {|obj| ... } ⇒ Array
#_enumerable_flat_map ⇒ Enumerator
Alias for Enumerable#flat_map.
Alias for Enumerable#grep.
Alias for Enumerable#grep_v.
#_enumerable_map {|obj| ... } ⇒ Array
#_enumerable_map ⇒ Enumerator
Alias for Enumerable#map.
#_enumerable_reject {|obj| ... } ⇒ Array
#_enumerable_reject ⇒ Enumerator
Alias for Enumerable#reject.
#_enumerable_select {|obj| ... } ⇒ Array
#_enumerable_select ⇒ Enumerator
Alias for Enumerable#select.
#_enumerable_take(n) ⇒ Array
Alias for Enumerable#take.
#_enumerable_take_while {|obj| ... } ⇒ Array
#_enumerable_take_while ⇒ Enumerator
Alias for Enumerable#take_while.
Alias for Enumerable#uniq.
#_enumerable_with_index(offset = 0) {|(*args), idx| ... } (private)
#_enumerable_with_index(offset = 0)
Alias for Enumerator#with_index.
#_enumerable_zip(arg, ...) ⇒ an_array_of_array
#_enumerable_zip(arg, ...) {|arr| ... } ⇒ nil
an_array_of_array
#_enumerable_zip(arg, ...) {|arr| ... } ⇒ nil
Alias for Enumerable#zip.
#chunk(*args) Also known as: #slice_before, #slice_after, #slice_when, #chunk_while
[ GitHub ]# File 'enumerator.c', line 2760
static VALUE lazy_super(int argc, VALUE *argv, VALUE lazy) { return enumerable_lazy(rb_call_super(argc, argv)); }
#chunk_while(*args)
Alias for #chunk.
#collect
[ GitHub ]
#collect_concat {|obj| ... } ⇒ Lazy
#flat_map {|obj| ... } ⇒ Lazy
Lazy
#flat_map {|obj| ... } ⇒ Lazy
Alias for #flat_map.
#drop(n)
[ GitHub ]# File 'enumerator.c', line 2542
static VALUE lazy_drop(VALUE obj, VALUE n) { long len = NUM2LONG(n); VALUE argv[2]; argv[0] = sym_each; argv[1] = n; if (len < 0) { rb_raise(rb_eArgError, "attempt to drop negative size"); } return lazy_add_method(obj, 2, argv, n, rb_ary_new3(1, n), &lazy_drop_funcs); }
#drop_while
[ GitHub ]#eager ⇒ Enumerator
Returns a non-lazy ::Enumerator
converted from the lazy enumerator.
# File 'enumerator.c', line 1955
static VALUE lazy_eager(VALUE self) { return enumerator_init(enumerator_allocate(rb_cEnumerator), self, sym_each, 0, 0, lazy_eager_size, Qnil, 0); }
#to_enum(method = :each, *args) ⇒ Lazy
#enum_for(method = :each, *args) ⇒ Lazy
#to_enum(method = :each, *args) {|*args| ... } ⇒ Lazy
#enum_for(method = :each, *args) {|*args| ... } ⇒ Lazy
Lazy
#enum_for(method = :each, *args) ⇒ Lazy
#to_enum(method = :each, *args) {|*args| ... } ⇒ Lazy
#enum_for(method = :each, *args) {|*args| ... } ⇒ Lazy
Alias for #to_enum.
#filter
[ GitHub ]#filter_map
[ GitHub ]#find_all
[ GitHub ]
#collect_concat {|obj| ... } ⇒ Lazy
#flat_map {|obj| ... } ⇒ Lazy
Also known as: #collect_concat
Lazy
#flat_map {|obj| ... } ⇒ Lazy
Returns a new lazy enumerator with the concatenated results of running block
once for every element in the lazy enumerator.
["foo", "bar"].lazy.flat_map {|i| i.each_char.lazy}.force
#=> ["f", "o", "o", "b", "a", "r"]
A value x
returned by block
is decomposed if either of the following conditions is true:
-
x
responds to both each and force, which means thatx
is a lazy enumerator. -
x
is an array or responds to to_ary.
Otherwise, x
is contained as-is in the return value.
[{a:1}, {b:2}].lazy.flat_map {|i| i}.force
#=> [{:a=>1}, {:b=>2}]
# File 'enumerator.c', line 2100
static VALUE lazy_flat_map(VALUE obj) { if (!rb_block_given_p()) { rb_raise(rb_eArgError, "tried to call lazy flat_map without a block"); } return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, lazy_flat_map_proc, 0), Qnil, 0); }
Alias for #to_a.
#grep
[ GitHub ]#grep_v
[ GitHub ]
#lazy ⇒ Lazy
Returns self.
# File 'enumerator.c', line 2773
static VALUE lazy_lazy(VALUE obj) { return obj; }
#map
[ GitHub ]#reject
[ GitHub ]#select
[ GitHub ]#slice_after(*args)
Alias for #chunk.
#slice_before(*args)
Alias for #chunk.
#slice_when(*args)
Alias for #chunk.
#take(n)
[ GitHub ]# File 'enumerator.c', line 2446
static VALUE lazy_take(VALUE obj, VALUE n) { long len = NUM2LONG(n); int argc = 0; VALUE argv[2]; if (len < 0) { rb_raise(rb_eArgError, "attempt to take negative size"); } if (len == 0) { argv[0] = sym_cycle; argv[1] = INT2NUM(0); argc = 2; } return lazy_add_method(obj, argc, argv, n, rb_ary_new3(1, n), &lazy_take_funcs); }
#take_while
[ GitHub ]Also known as: #force
Expands #lazy enumerator to an array. See Enumerable#to_a.
# File 'enumerator.c', line 1787
static VALUE lazy_to_a(VALUE self) { }
#to_enum(method = :each, *args) ⇒ Lazy
#enum_for(method = :each, *args) ⇒ Lazy
#to_enum(method = :each, *args) {|*args| ... } ⇒ Lazy
#enum_for(method = :each, *args) {|*args| ... } ⇒ Lazy
Also known as: #enum_for
Lazy
#enum_for(method = :each, *args) ⇒ Lazy
#to_enum(method = :each, *args) {|*args| ... } ⇒ Lazy
#enum_for(method = :each, *args) {|*args| ... } ⇒ Lazy
Similar to Object#to_enum, except it returns a lazy enumerator. This makes it easy to define ::Enumerable
methods that will naturally remain lazy if called from a lazy enumerator.
For example, continuing from the example in Object#to_enum:
# See Object#to_enum for the definition of repeat
r = 1..Float::INFINITY
r.repeat(2).first(5) # => [1, 1, 2, 2, 3]
r.repeat(2).class # => Enumerator
r.repeat(2).map{|n| n ** 2}.first(5) # => endless loop!
# works naturally on lazy enumerator:
r.lazy.repeat(2).class # => Enumerator::Lazy
r.lazy.repeat(2).map{|n| n ** 2}.first(5) # => [1, 1, 4, 4, 9]
# File 'enumerator.c', line 1923
static VALUE lazy_to_enum(int argc, VALUE *argv, VALUE self) { VALUE lazy, meth = sym_each, super_meth; if (argc > 0) { --argc; meth = *argv++; } if (RTEST((super_meth = rb_hash_aref(lazy_use_super_method, meth)))) { meth = super_meth; } lazy = lazy_to_enum_i(self, meth, argc, argv, 0, PASS_KW_SPLAT); if (rb_block_given_p()) { enumerator_ptr(lazy)->size = rb_block_proc(); } return lazy; }
#uniq
[ GitHub ]
#zip(arg, ...) ⇒ Lazy
#zip(arg, ...) {|arr| ... } ⇒ nil
Lazy
#zip(arg, ...) {|arr| ... } ⇒ nil
Like Enumerable#zip, but chains operation to be lazy-evaluated. However, if a block is given to zip, values are enumerated immediately.
# File 'enumerator.c', line 2371
static VALUE lazy_zip(int argc, VALUE *argv, VALUE obj) { VALUE ary, v; long i; rb_block_call_func *func = lazy_zip_arrays_func; if (rb_block_given_p()) { return rb_call_super(argc, argv); } ary = rb_ary_new2(argc); for (i = 0; i < argc; i++) { v = rb_check_array_type(argv[i]); if (NIL_P(v)) { for (; i < argc; i++) { if (!rb_respond_to(argv[i], id_each)) { rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (must respond to :each)", rb_obj_class(argv[i])); } } ary = rb_ary_new4(argc, argv); func = lazy_zip_func; break; } rb_ary_push(ary, v); } return lazy_set_method(rb_block_call(rb_cLazy, id_new, 1, &obj, func, ary), ary, lazy_receiver_size); }