Module: Enumerable
- Included in:
- Array, Dir, Enumerator, Enumerator::Generator, Hash, IO, ObjectSpace::WeakMap, Range, Struct
- Defined in:
- enum.c
Overview
What’s Here
Module Enumerable provides methods that are useful to a collection class for:
Methods for Querying
These methods return information about the Enumerable other than the elements themselves:
-
#member? (aliased as #include?): Returns
true
ifself == object
,false
otherwise. -
#all?: Returns
true
if all elements meet a specified criterion;false
otherwise. -
#any?: Returns
true
if any element meets a specified criterion;false
otherwise. -
#none?: Returns
true
if no element meets a specified criterion;false
otherwise. -
#one?: Returns
true
if exactly one element meets a specified criterion;false
otherwise. -
#count: Returns the count of elements, based on an argument or block criterion, if given.
-
#tally: Returns a new Hash containing the counts of occurrences of each element.
Methods for Fetching
These methods return entries from the Enumerable, without modifying it:
Leading, trailing, or all elements:
-
#to_a (aliased as #entries): Returns all elements.
-
#first: Returns the first element or leading elements.
-
#take: Returns a specified number of leading elements.
-
#drop: Returns a specified number of trailing elements.
-
#take_while: Returns leading elements as specified by the given block.
-
#drop_while: Returns trailing elements as specified by the given block.
Minimum and maximum value elements:
-
#min: Returns the elements whose values are smallest among the elements, as determined by
#<=>
or a given block. -
#max: Returns the elements whose values are largest among the elements, as determined by
#<=>
or a given block. -
#minmax: Returns a 2-element Array containing the smallest and largest elements.
-
#min_by: Returns the smallest element, as determined by the given block.
-
#max_by: Returns the largest element, as determined by the given block.
-
#minmax_by: Returns the smallest and largest elements, as determined by the given block.
Groups, slices, and partitions:
-
#group_by: Returns a Hash that partitions the elements into groups.
-
#partition: Returns elements partitioned into two new Arrays, as determined by the given block.
-
#slice_after: Returns a new Enumerator whose entries are a partition of
self
, based either on a givenobject
or a given block. -
#slice_before: Returns a new Enumerator whose entries are a partition of
self
, based either on a givenobject
or a given block. -
#slice_when: Returns a new Enumerator whose entries are a partition of
self
based on the given block. -
#chunk: Returns elements organized into chunks as specified by the given block.
-
#chunk_while: Returns elements organized into chunks as specified by the given block.
Methods for Searching and Filtering
These methods return elements that meet a specified criterion:
-
#find (aliased as #detect): Returns an element selected by the block.
-
#find_all (aliased as #filter, #select): Returns elements selected by the block.
-
#find_index: Returns the index of an element selected by a given object or block.
-
#reject: Returns elements not rejected by the block.
-
#uniq: Returns elements that are not duplicates.
Methods for Sorting
These methods return elements in sorted order:
-
#sort: Returns the elements, sorted by
#<=>
or the given block. -
#sort_by: Returns the elements, sorted by the given block.
Methods for Iterating
-
#each_entry: Calls the block with each successive element (slightly different from #each).
-
#each_with_index: Calls the block with each successive element and its index.
-
#each_with_object: Calls the block with each successive element and a given object.
-
#each_slice: Calls the block with successive non-overlapping slices.
-
#each_cons: Calls the block with successive overlapping slices. (different from #each_slice).
-
#reverse_each: Calls the block with each successive element, in reverse order.
Other Methods
-
#collect (aliased as #map): Returns objects returned by the block.
-
#filter_map: Returns truthy objects returned by the block.
-
#flat_map (aliased as #collect_concat): Returns flattened objects returned by the block.
-
#grep: Returns elements selected by a given object or objects returned by a given block.
-
#grep_v: Returns elements selected by a given object or objects returned by a given block.
-
#inject (aliased as #reduce): Returns the object formed by combining all elements.
-
#sum: Returns the sum of the elements, using method
+
. -
#zip: Combines each element with elements from other enumerables; returns the n-tuples or calls the block with each.
-
#cycle: Calls the block with each element, cycling repeatedly.
Usage
To use module Enumerable in a collection class:
-
Include it:
include Enumerable
-
Implement method
#each
which must yield successive elements of the collection. The method will be called by almost any Enumerable method.
Example:
class Foo
include Enumerable
def each
yield 1
yield 1, 2
yield
end
end
Foo.new.each_entry{ |element| p element }
Output:
1
[1, 2]
nil
Enumerable in Ruby Classes
These Ruby core classes include (or extend) Enumerable:
-
ARGF
-
Array
-
Dir
-
Enumerator
-
ENV (extends)
-
Hash
-
IO
-
Range
-
Struct
These Ruby standard library classes include Enumerable:
-
CSV
-
CSV::Table
-
CSV::Row
-
Set
Virtually all methods in Enumerable call method #each
in the including class:
-
Hash#each
yields the next key-value pair as a 2-element Array. -
Struct#each
yields the next name-value pair as a 2-element Array. -
For the other classes above,
#each
yields the next object from the collection.
About the Examples
The example code snippets for the Enumerable methods:
-
Always show the use of one or more Array-like classes (often Array itself).
-
Sometimes show the use of a Hash-like class. For some methods, though, the usage would not make sense, and so it is not shown. Example: #tally would find exactly one of each Hash entry.
Instance Method Summary collapse
-
#all?(*args) ⇒ Object
Returns whether every element meets a given criterion.
-
#any?(*args) ⇒ Object
Returns whether any element meets a given criterion.
-
#chain(*enums) ⇒ Object
Returns an enumerator object generated from this enumerator and given enumerables.
-
#chunk {|array| ... } ⇒ Object
Each element in the returned enumerator is a 2-element array consisting of:.
-
#chunk_while {|elt_before, elt_after| ... } ⇒ Object
Creates an enumerator for each chunked elements.
-
#collect ⇒ Object
Returns an array of objects returned by the block.
-
#collect_concat ⇒ Object
Returns an array of flattened objects returned by the block.
-
#compact ⇒ Array
Returns an array of all non-
nil
elements:. -
#count(*args) ⇒ Object
Returns the count of elements, based on an argument or block criterion, if given.
-
#cycle(*args) ⇒ Object
When called with positive integer argument
n
and a block, calls the block with each element, then does so again, until it has done son
times; returnsnil
:. -
#detect(*args) ⇒ Object
Returns the first element for which the block returns a truthy value.
-
#drop(n) ⇒ Array
For positive integer
n
, returns an array containing all but the firstn
elements:. -
#drop_while ⇒ Object
Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements after that point:.
-
#each_cons(n) ⇒ Object
Calls the block with each successive overlapped
n
-tuple of elements; returnsself
:. -
#each_entry(*args) ⇒ Object
Calls the given block with each element, converting multiple values from yield to an array; returns
self
:. -
#each_slice(n) ⇒ Object
Calls the block with each successive disjoint
n
-tuple of elements; returnsself
:. -
#each_with_index(*args) ⇒ Object
Invoke
self.each
with*args
. -
#each_with_object(memo) ⇒ Object
Calls the block once for each element, passing both the element and the given object:.
-
#to_a(*args) ⇒ Array
Returns an array containing the items in
self
:. -
#filter ⇒ Object
Returns an array containing elements selected by the block.
-
#filter_map ⇒ Object
Returns an array containing truthy elements returned by the block.
-
#find(*args) ⇒ Object
Returns the first element for which the block returns a truthy value.
-
#find_all ⇒ Object
Returns an array containing elements selected by the block.
-
#find_index(*args) ⇒ Object
Returns the index of the first element that meets a specified criterion, or
nil
if no such element is found. -
#first(*args) ⇒ Object
Returns the first element or elements.
-
#flat_map ⇒ Object
Returns an array of flattened objects returned by the block.
-
#grep(pat) ⇒ Object
Returns an array of objects based elements of
self
that match the given pattern. -
#grep_v(pat) ⇒ Object
Returns an array of objects based on elements of
self
that don’t match the given pattern. -
#group_by ⇒ Object
With a block given returns a hash:.
-
#include?(object) ⇒ Boolean
Returns whether for any element
object == element
:. -
#inject(*args) ⇒ Object
Returns the result of applying a reducer to an initial value and the first element of the Enumerable.
-
#lazy ⇒ Object
Returns an Enumerator::Lazy, which redefines most Enumerable methods to postpone enumeration and enumerate values only on an as-needed basis.
-
#map ⇒ Object
Returns an array of objects returned by the block.
-
#max(*args) ⇒ Object
Returns the element with the maximum element according to a given criterion.
-
#max_by(*args) ⇒ Object
Returns the elements for which the block returns the maximum values.
-
#include?(object) ⇒ Boolean
Returns whether for any element
object == element
:. -
#min(*args) ⇒ Object
Returns the element with the minimum element according to a given criterion.
-
#min_by(*args) ⇒ Object
Returns the elements for which the block returns the minimum values.
-
#minmax ⇒ Object
Returns a 2-element array containing the minimum and maximum elements according to a given criterion.
-
#minmax_by ⇒ Object
Returns a 2-element array containing the elements for which the block returns minimum and maximum values:.
-
#none?(*args) ⇒ Object
Returns whether no element meets a given criterion.
-
#one?(*args) ⇒ Object
Returns whether exactly one element meets a given criterion.
-
#partition ⇒ Object
With a block given, returns an array of two arrays:.
-
#reduce(*args) ⇒ Object
Returns the result of applying a reducer to an initial value and the first element of the Enumerable.
-
#reject ⇒ Object
Returns an array of objects rejected by the block.
-
#reverse_each(*args) ⇒ Object
With a block given, calls the block with each element, but in reverse order; returns
self
:. -
#select ⇒ Object
Returns an array containing elements selected by the block.
-
#slice_after(*args) ⇒ Object
Creates an enumerator for each chunked elements.
-
#slice_before(*args) ⇒ Object
With argument
pattern
, returns an enumerator that uses the pattern to partition elements into arrays (“slices”). -
#slice_when {|elt_before, elt_after| ... } ⇒ Object
Creates an enumerator for each chunked elements.
-
#sort ⇒ Object
Returns an array containing the sorted elements of
self
. -
#sort_by ⇒ Object
With a block given, returns an array of elements of
self
, sorted according to the value returned by the block for each element. -
#sum(*args) ⇒ Object
With no block given, returns the sum of
initial_value
and the elements:. -
#take(n) ⇒ Array
For non-negative integer
n
, returns the firstn
elements:. -
#take_while ⇒ Object
Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements up to that point:.
-
#tally(hash = {}) ⇒ Hash
When argument
hash
is not given, returns a new hash whose keys are the distinct elements inself
; each integer value is the count of occurrences of each element:. -
#to_a(*args) ⇒ Array
Returns an array containing the items in
self
:. -
#to_h(*args) ⇒ Object
When
self
consists of 2-element arrays, returns a hash each of whose entries is the key-value pair formed from one of those arrays:. -
#uniq ⇒ Object
With no block, returns a new array containing only unique elements; the array has no two elements
e0
ande1
such thate0.eql?(e1)
:. -
#zip(*args) ⇒ Object
With no block given, returns a new array
new_array
of size self.size whose elements are arrays.
Instance Method Details
#all? ⇒ Boolean #all?(pattern) ⇒ Boolean #all? {|element| ... } ⇒ Boolean
Returns whether every element meets a given criterion.
If self
has no element, returns true
and argument or block are not used.
With no argument and no block, returns whether every element is truthy:
(1..4).all? # => true
%w[a b c d].all? # => true
[1, 2, nil].all? # => false
['a','b', false].all? # => false
[].all? # => true
With argument pattern
and no block, returns whether for each element element
, pattern === element
:
(1..4).all?(Integer) # => true
(1..4).all?(Numeric) # => true
(1..4).all?(Float) # => false
%w[bar baz bat bam].all?(/ba/) # => true
%w[bar baz bat bam].all?(/bar/) # => false
%w[bar baz bat bam].all?('ba') # => false
{foo: 0, bar: 1, baz: 2}.all?(Array) # => true
{foo: 0, bar: 1, baz: 2}.all?(Hash) # => false
[].all?(Integer) # => true
With a block given, returns whether the block returns a truthy value for every element:
(1..4).all? {|element| element < 5 } # => true
(1..4).all? {|element| element < 4 } # => false
{foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 3 } # => true
{foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 2 } # => false
Related: #any?, #none? #one?.
1855 1856 1857 1858 1859 1860 1861 1862 |
# File 'enum.c', line 1855
static VALUE
enum_all(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(all);
return memo->v1;
}
|
#any? ⇒ Boolean #any?(pattern) ⇒ Boolean #any? {|element| ... } ⇒ Boolean
Returns whether any element meets a given criterion.
If self
has no element, returns false
and argument or block are not used.
With no argument and no block, returns whether any element is truthy:
(1..4).any? # => true
%w[a b c d].any? # => true
[1, false, nil].any? # => true
[].any? # => false
With argument pattern
and no block, returns whether for any element element
, pattern === element
:
[nil, false, 0].any?(Integer) # => true
[nil, false, 0].any?(Numeric) # => true
[nil, false, 0].any?(Float) # => false
%w[bar baz bat bam].any?(/m/) # => true
%w[bar baz bat bam].any?(/foo/) # => false
%w[bar baz bat bam].any?('ba') # => false
{foo: 0, bar: 1, baz: 2}.any?(Array) # => true
{foo: 0, bar: 1, baz: 2}.any?(Hash) # => false
[].any?(Integer) # => false
With a block given, returns whether the block returns a truthy value for any element:
(1..4).any? {|element| element < 2 } # => true
(1..4).any? {|element| element < 1 } # => false
{foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 1 } # => true
{foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 0 } # => false
Related: #all?, #none?, #one?.
1917 1918 1919 1920 1921 1922 1923 1924 |
# File 'enum.c', line 1917
static VALUE
enum_any(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qfalse);
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(any);
return memo->v1;
}
|
#chain(*enums) ⇒ Object
Returns an enumerator object generated from this enumerator and given enumerables.
e = (1..3).chain([4, 5])
e.to_a #=> [1, 2, 3, 4, 5]
3368 3369 3370 3371 3372 3373 3374 |
# File 'enumerator.c', line 3368
static VALUE
enum_chain(int argc, VALUE *argv, VALUE obj)
{
VALUE enums = rb_ary_new_from_values(1, &obj);
rb_ary_cat(enums, argv, argc);
return new_enum_chain(enums);
}
|
#chunk {|array| ... } ⇒ Object
Each element in the returned enumerator is a 2-element array consisting of:
-
A value returned by the block.
-
An array (“chunk”) containing the element for which that value was returned, and all following elements for which the block returned the same value:
So that:
-
Each block return value that is different from its predecessor begins a new chunk.
-
Each block return value that is the same as its predecessor continues the same chunk.
Example:
e = (0..10).chunk {|i| (i / 3).floor } # => #<Enumerator: ...>
# The enumerator elements.
e.next # => [0, [0, 1, 2]]
e.next # => [1, [3, 4, 5]]
e.next # => [2, [6, 7, 8]]
e.next # => [3, [9, 10]]
Method chunk
is especially useful for an enumerable that is already sorted. This example counts words for each initial letter in a large array of words:
# Get sorted words from a web page.
url = 'https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt'
words = URI::open(url).readlines
# Make chunks, one for each letter.
e = words.chunk {|word| word.upcase[0] } # => #<Enumerator: ...>
# Display 'A' through 'F'.
e.each {|c, words| p [c, words.length]; break if c == 'F' }
Output:
["A", 17096]
["B", 11070]
["C", 19901]
["D", 10896]
["E", 8736]
["F", 6860]
You can use the special symbol :_alone
to force an element into its own separate chuck:
a = [0, 0, 1, 1]
e = a.chunk{|i| i.even? ? :_alone : true }
e.to_a # => [[:_alone, [0]], [:_alone, [0]], [true, [1, 1]]]
For example, you can put each line that contains a URL into its own chunk:
pattern = /http/
open(filename) { |f|
f.chunk { |line| line =~ pattern ? :_alone : true }.each { |key, lines|
pp lines
}
}
You can use the special symbol :_separator
or nil
to force an element to be ignored (not included in any chunk):
a = [0, 0, -1, 1, 1]
e = a.chunk{|i| i < 0 ? :_separator : true }
e.to_a # => [[true, [0, 0]], [true, [1, 1]]]
Note that the separator does end the chunk:
a = [0, 0, -1, 1, -1, 1]
e = a.chunk{|i| i < 0 ? :_separator : true }
e.to_a # => [[true, [0, 0]], [true, [1]], [true, [1]]]
For example, the sequence of hyphens in svn log can be eliminated as follows:
sep = "-"*72 + "\n"
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"]
# ...
Paragraphs separated by empty lines can be parsed as follows:
File.foreach("README").chunk { |line|
/\A\s*\z/ !~ line || nil
}.each { |_, lines|
pp lines
}
3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 |
# File 'enum.c', line 3993
static VALUE
enum_chunk(VALUE enumerable)
{
VALUE enumerator;
RETURN_SIZED_ENUMERATOR(enumerable, 0, 0, enum_size);
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_chunk_enumerable, enumerable);
rb_ivar_set(enumerator, id_chunk_categorize, rb_block_proc());
rb_block_call(enumerator, idInitialize, 0, 0, chunk_i, enumerator);
return enumerator;
}
|
#chunk_while {|elt_before, elt_after| ... } ⇒ Object
Creates an enumerator for each chunked elements. The beginnings of chunks are defined by the block.
This method splits each chunk using adjacent elements, elt_before and elt_after, in the receiver enumerator. This method split chunks between elt_before and elt_after where the block returns false
.
The block is called the length of the receiver enumerator minus one.
The result enumerator yields the chunked elements as an array. So each
method can be called as follows:
enum.chunk_while { |elt_before, elt_after| bool }.each { |ary| ... }
Other methods of the Enumerator class and Enumerable module, such as to_a
, map
, etc., are also usable.
For example, one-by-one increasing subsequence can be chunked as follows:
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"
Increasing (non-decreasing) subsequence can be chunked as follows:
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]]
Adjacent evens and odds can be chunked as follows: (Enumerable#chunk is another way to do it.)
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 does the same, except splitting when the block returns true
instead of false
.
4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 |
# File 'enum.c', line 4567
static VALUE
enum_chunk_while(VALUE enumerable)
{
VALUE enumerator;
VALUE pred;
pred = rb_block_proc();
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicewhen_enum, enumerable);
rb_ivar_set(enumerator, id_slicewhen_pred, pred);
rb_ivar_set(enumerator, id_slicewhen_inverted, Qtrue);
rb_block_call(enumerator, idInitialize, 0, 0, slicewhen_i, enumerator);
return enumerator;
}
|
#map {|element| ... } ⇒ Array #map ⇒ Object
Returns an array of objects returned by the block.
With a block given, calls the block with successive elements; returns an array of the objects returned by the block:
(0..4).map {|i| i*i } # => [0, 1, 4, 9, 16]
{foo: 0, bar: 1, baz: 2}.map {|key, value| value*2} # => [0, 2, 4]
With no block given, returns an Enumerator.
656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
# File 'enum.c', line 656
static VALUE
enum_collect(VALUE obj)
{
VALUE ary;
int min_argc, max_argc;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
min_argc = rb_block_min_max_arity(&max_argc);
rb_lambda_call(obj, id_each, 0, 0, collect_i, min_argc, max_argc, ary);
return ary;
}
|
#flat_map {|element| ... } ⇒ Array #flat_map ⇒ Object
Returns an array of flattened objects returned by the block.
With a block given, calls the block with successive elements; returns a flattened array of objects returned by the block:
[0, 1, 2, 3].flat_map {|element| -element } # => [0, -1, -2, -3]
[0, 1, 2, 3].flat_map {|element| [element, -element] } # => [0, 0, 1, -1, 2, -2, 3, -3]
[[0, 1], [2, 3]].flat_map {|e| e + [100] } # => [0, 1, 100, 2, 3, 100]
{foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] } # => [:foo, 0, :bar, 1, :baz, 2]
With no block given, returns an Enumerator.
Alias: #collect_concat.
707 708 709 710 711 712 713 714 715 716 717 718 |
# File 'enum.c', line 707
static VALUE
enum_flat_map(VALUE obj)
{
VALUE ary;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, flat_map_i, ary);
return ary;
}
|
#compact ⇒ Array
Returns an array of all non-nil
elements:
a = [nil, 0, nil, 'a', false, nil, false, nil, 'a', nil, 0, nil]
a.compact # => [0, "a", false, false, "a", 0]
4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 |
# File 'enum.c', line 4927
static VALUE
enum_compact(VALUE obj)
{
VALUE ary;
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, compact_i, ary);
return ary;
}
|
#count ⇒ Integer #count(object) ⇒ Integer #count {|element| ... } ⇒ Integer
Returns the count of elements, based on an argument or block criterion, if given.
With no argument and no block given, returns the number of elements:
[0, 1, 2].count # => 3
{foo: 0, bar: 1, baz: 2}.count # => 3
With argument object
given, returns the number of elements that are ==
to object
:
[0, 1, 2, 1].count(1) # => 2
With a block given, calls the block with each element and returns the number of elements for which the block returns a truthy value:
[0, 1, 2, 3].count {|element| element < 2} # => 2
{foo: 0, bar: 1, baz: 2}.count {|key, value| value < 2} # => 2
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
# File 'enum.c', line 297
static VALUE
enum_count(int argc, VALUE *argv, VALUE obj)
{
VALUE item = Qnil;
struct MEMO *memo;
rb_block_call_func *func;
if (argc == 0) {
if (rb_block_given_p()) {
func = count_iter_i;
}
else {
func = count_all_i;
}
}
else {
rb_scan_args(argc, argv, "1", &item);
if (rb_block_given_p()) {
rb_warn("given block not used");
}
func = count_i;
}
memo = MEMO_NEW(item, 0, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return imemo_count_value(memo);
}
|
#cycle(n = nil) {|element| ... } ⇒ nil #cycle(n = nil) ⇒ Object
When called with positive integer argument n
and a block, calls the block with each element, then does so again, until it has done so n
times; returns nil
:
a = []
(1..4).cycle(3) {|element| a.push(element) } # => nil
a # => [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
a = []
('a'..'d').cycle(2) {|element| a.push(element) }
a # => ["a", "b", "c", "d", "a", "b", "c", "d"]
a = []
{foo: 0, bar: 1, baz: 2}.cycle(2) {|element| a.push(element) }
a # => [[:foo, 0], [:bar, 1], [:baz, 2], [:foo, 0], [:bar, 1], [:baz, 2]]
If count is zero or negative, does not call the block.
When called with a block and n
is nil
, cycles forever.
When no block is given, returns an Enumerator.
3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 |
# File 'enum.c', line 3779
static VALUE
enum_cycle(int argc, VALUE *argv, VALUE obj)
{
VALUE ary;
VALUE nv = Qnil;
long n, i, len;
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_cycle_size);
if (!argc || NIL_P(nv = argv[0])) {
n = -1;
}
else {
n = NUM2LONG(nv);
if (n <= 0) return Qnil;
}
ary = rb_ary_new();
RBASIC_CLEAR_CLASS(ary);
rb_block_call(obj, id_each, 0, 0, cycle_i, ary);
len = RARRAY_LEN(ary);
if (len == 0) return Qnil;
while (n < 0 || 0 < --n) {
for (i=0; i<len; i++) {
enum_yield_array(RARRAY_AREF(ary, i));
}
}
return Qnil;
}
|
#find(if_none_proc = nil) {|element| ... } ⇒ Object? #find(if_none_proc = nil) ⇒ Object
Returns the first element for which the block returns a truthy value.
With a block given, calls the block with successive elements of the collection; returns the first element for which the block returns a truthy value:
(0..9).find {|element| element > 2} # => 3
If no such element is found, calls if_none_proc
and returns its return value.
(0..9).find(proc {false}) {|element| element > 12} # => false
{foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') } # => [:bar, 1]
{foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') } # => []
With no block given, returns an Enumerator.
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'enum.c', line 376
static VALUE
enum_find(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE if_none;
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
RETURN_ENUMERATOR(obj, argc, argv);
memo = MEMO_NEW(Qundef, 0, 0);
if (rb_block_pair_yield_optimizable())
rb_block_call2(obj, id_each, 0, 0, find_i_fast, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
else
rb_block_call2(obj, id_each, 0, 0, find_i, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
if (memo->u3.cnt) {
return memo->v1;
}
if (!NIL_P(if_none)) {
return rb_funcallv(if_none, id_call, 0, 0);
}
return Qnil;
}
|
#drop(n) ⇒ Array
For positive integer n
, returns an array containing all but the first n
elements:
r = (1..4)
r.drop(3) # => [4]
r.drop(2) # => [3, 4]
r.drop(1) # => [2, 3, 4]
r.drop(0) # => [1, 2, 3, 4]
r.drop(50) # => []
h = {foo: 0, bar: 1, baz: 2, bat: 3}
h.drop(2) # => [[:baz, 2], [:bat, 3]]
3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 |
# File 'enum.c', line 3656
static VALUE
enum_drop(VALUE obj, VALUE n)
{
VALUE result;
struct MEMO *memo;
long len = NUM2LONG(n);
if (len < 0) {
rb_raise(rb_eArgError, "attempt to drop negative size");
}
result = rb_ary_new();
memo = MEMO_NEW(result, 0, len);
rb_block_call(obj, id_each, 0, 0, drop_i, (VALUE)memo);
return result;
}
|
#drop_while {|element| ... } ⇒ Array #drop_while ⇒ Object
Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements after that point:
(1..4).drop_while{|i| i < 3 } # => [3, 4]
h = {foo: 0, bar: 1, baz: 2}
a = h.drop_while{|element| key, value = *element; value < 2 }
a # => [[:baz, 2]]
With no block given, returns an Enumerator.
3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 |
# File 'enum.c', line 3708
static VALUE
enum_drop_while(VALUE obj)
{
VALUE result;
struct MEMO *memo;
RETURN_ENUMERATOR(obj, 0, 0);
result = rb_ary_new();
memo = MEMO_NEW(result, 0, FALSE);
rb_block_call(obj, id_each, 0, 0, drop_while_i, (VALUE)memo);
return result;
}
|
#each_cons(n) { ... } ⇒ self #each_cons(n) ⇒ Object
Calls the block with each successive overlapped n
-tuple of elements; returns self
:
a = []
(1..5).each_cons(3) {|element| a.push(element) }
a # => [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
a = []
h = {foo: 0, bar: 1, baz: 2, bam: 3}
h.each_cons(2) {|element| a.push(element) }
a # => [[[:foo, 0], [:bar, 1]], [[:bar, 1], [:baz, 2]], [[:baz, 2], [:bam, 3]]]
With no block given, returns an Enumerator.
3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 |
# File 'enum.c', line 3297
static VALUE
enum_each_cons(VALUE obj, VALUE n)
{
long size = NUM2LONG(n);
struct MEMO *memo;
int arity;
if (size <= 0) rb_raise(rb_eArgError, "invalid size");
RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_cons_size);
arity = rb_block_arity();
if (enum_size_over_p(obj, size)) return obj;
memo = MEMO_NEW(rb_ary_new2(size), dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_cons_i, (VALUE)memo);
return obj;
}
|
#each_entry(*args) {|element| ... } ⇒ self #each_entry(*args) ⇒ Object
Calls the given block with each element, converting multiple values from yield to an array; returns self
:
a = []
(1..4).each_entry {|element| a.push(element) } # => 1..4
a # => [1, 2, 3, 4]
a = []
h = {foo: 0, bar: 1, baz:2}
h.each_entry {|element| a.push(element) }
# => {:foo=>0, :bar=>1, :baz=>2}
a # => [[:foo, 0], [:bar, 1], [:baz, 2]]
class Foo
include Enumerable
def each
yield 1
yield 1, 2
yield
end
end
Foo.new.each_entry {|yielded| p yielded }
Output:
1
[1, 2]
nil
With no block given, returns an Enumerator.
3129 3130 3131 3132 3133 3134 3135 |
# File 'enum.c', line 3129
static VALUE
enum_each_entry(int argc, VALUE *argv, VALUE obj)
{
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
rb_block_call(obj, id_each, argc, argv, each_val_i, 0);
return obj;
}
|
#each_slice(n) { ... } ⇒ self #each_slice(n) ⇒ Object
Calls the block with each successive disjoint n
-tuple of elements; returns self
:
a = []
(1..10).each_slice(3) {|tuple| a.push(tuple) }
a # => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
a = []
h = {foo: 0, bar: 1, baz: 2, bat: 3, bam: 4}
h.each_slice(2) {|tuple| a.push(tuple) }
a # => [[[:foo, 0], [:bar, 1]], [[:baz, 2], [:bat, 3]], [[:bam, 4]]]
With no block given, returns an Enumerator.
3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 |
# File 'enum.c', line 3219
static VALUE
enum_each_slice(VALUE obj, VALUE n)
{
long size = NUM2LONG(n);
VALUE ary;
struct MEMO *memo;
int arity;
if (size <= 0) rb_raise(rb_eArgError, "invalid slice size");
RETURN_SIZED_ENUMERATOR(obj, 1, &n, enum_each_slice_size);
size = limit_by_enum_size(obj, size);
ary = rb_ary_new2(size);
arity = rb_block_arity();
memo = MEMO_NEW(ary, dont_recycle_block_arg(arity), size);
rb_block_call(obj, id_each, 0, 0, each_slice_i, (VALUE)memo);
ary = memo->v1;
if (RARRAY_LEN(ary) > 0) rb_yield(ary);
return obj;
}
|
#each_with_index(*args) {|element, i| ... } ⇒ self #each_with_index(*args) ⇒ Object
Invoke self.each
with *args
. With a block given, the block receives each element and its index; returns self
:
h = {}
(1..4).each_with_index {|element, i| h[element] = i } # => 1..4
h # => {1=>0, 2=>1, 3=>2, 4=>3}
h = {}
%w[a b c d].each_with_index {|element, i| h[element] = i }
# => ["a", "b", "c", "d"]
h # => {"a"=>0, "b"=>1, "c"=>2, "d"=>3}
a = []
h = {foo: 0, bar: 1, baz: 2}
h.each_with_index {|element, i| a.push([i, element]) }
# => {:foo=>0, :bar=>1, :baz=>2}
a # => [[0, [:foo, 0]], [1, [:bar, 1]], [2, [:baz, 2]]]
With no block given, returns an Enumerator.
3023 3024 3025 3026 3027 3028 3029 3030 |
# File 'enum.c', line 3023
static VALUE
enum_each_with_index(int argc, VALUE *argv, VALUE obj)
{
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
rb_block_call(obj, id_each, argc, argv, each_with_index_i, INT2FIX(0));
return obj;
}
|
#each_with_object(object) {|(*args), memo_object| ... } ⇒ Object #each_with_object(object) ⇒ Object
Calls the block once for each element, passing both the element and the given object:
(1..4).each_with_object([]) {|i, a| a.push(i**2) }
# => [1, 4, 9, 16]
{foo: 0, bar: 1, baz: 2}.each_with_object({}) {|(k, v), h| h[v] = k }
# => {0=>:foo, 1=>:bar, 2=>:baz}
With no block given, returns an Enumerator.
3338 3339 3340 3341 3342 3343 3344 3345 3346 |
# File 'enum.c', line 3338
static VALUE
enum_each_with_object(VALUE obj, VALUE memo)
{
RETURN_SIZED_ENUMERATOR(obj, 1, &memo, enum_size);
rb_block_call(obj, id_each, 0, 0, each_with_object_i, memo);
return memo;
}
|
#to_a(*args) ⇒ Array
Returns an array containing the items in self
:
(0..4).to_a # => [0, 1, 2, 3, 4]
729 730 731 732 733 734 735 736 737 |
# File 'enum.c', line 729
static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
{
VALUE ary = rb_ary_new();
rb_block_call_kw(obj, id_each, argc, argv, collect_all, ary, RB_PASS_CALLED_KEYWORDS);
return ary;
}
|
#select {|element| ... } ⇒ Array #select ⇒ Object
Returns an array containing elements selected by the block.
With a block given, calls the block with successive elements; returns an array of those elements for which the block returns a truthy value:
(0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9]
a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
a # => {:bar=>1, :baz=>2}
With no block given, returns an Enumerator.
Related: #reject.
527 528 529 530 531 532 533 534 535 536 537 538 |
# File 'enum.c', line 527
static VALUE
enum_find_all(VALUE obj)
{
VALUE ary;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
return ary;
}
|
#filter_map {|element| ... } ⇒ Array #filter_map ⇒ Object
Returns an array containing truthy elements returned by the block.
With a block given, calls the block with successive elements; returns an array containing each truthy value returned by the block:
(0..9).filter_map {|i| i * 2 if i.even? } # => [0, 4, 8, 12, 16]
{foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? } # => [:foo, :baz]
When no block given, returns an Enumerator.
568 569 570 571 572 573 574 575 576 577 578 579 |
# File 'enum.c', line 568
static VALUE
enum_filter_map(VALUE obj)
{
VALUE ary;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, filter_map_i, ary);
return ary;
}
|
#find(if_none_proc = nil) {|element| ... } ⇒ Object? #find(if_none_proc = nil) ⇒ Object
Returns the first element for which the block returns a truthy value.
With a block given, calls the block with successive elements of the collection; returns the first element for which the block returns a truthy value:
(0..9).find {|element| element > 2} # => 3
If no such element is found, calls if_none_proc
and returns its return value.
(0..9).find(proc {false}) {|element| element > 12} # => false
{foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') } # => [:bar, 1]
{foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') } # => []
With no block given, returns an Enumerator.
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 |
# File 'enum.c', line 376
static VALUE
enum_find(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE if_none;
if_none = rb_check_arity(argc, 0, 1) ? argv[0] : Qnil;
RETURN_ENUMERATOR(obj, argc, argv);
memo = MEMO_NEW(Qundef, 0, 0);
if (rb_block_pair_yield_optimizable())
rb_block_call2(obj, id_each, 0, 0, find_i_fast, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
else
rb_block_call2(obj, id_each, 0, 0, find_i, (VALUE)memo, RB_BLOCK_NO_USE_PACKED_ARGS);
if (memo->u3.cnt) {
return memo->v1;
}
if (!NIL_P(if_none)) {
return rb_funcallv(if_none, id_call, 0, 0);
}
return Qnil;
}
|
#select {|element| ... } ⇒ Array #select ⇒ Object
Returns an array containing elements selected by the block.
With a block given, calls the block with successive elements; returns an array of those elements for which the block returns a truthy value:
(0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9]
a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
a # => {:bar=>1, :baz=>2}
With no block given, returns an Enumerator.
Related: #reject.
527 528 529 530 531 532 533 534 535 536 537 538 |
# File 'enum.c', line 527
static VALUE
enum_find_all(VALUE obj)
{
VALUE ary;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
return ary;
}
|
#find_index(object) ⇒ Integer? #find_index {|element| ... } ⇒ Integer? #find_index ⇒ Object
Returns the index of the first element that meets a specified criterion, or nil
if no such element is found.
With argument object
given, returns the index of the first element that is ==
object
:
['a', 'b', 'c', 'b'].find_index('b') # => 1
With a block given, calls the block with successive elements; returns the first element for which the block returns a truthy value:
['a', 'b', 'c', 'b'].find_index {|element| element.start_with?('b') } # => 1
{foo: 0, bar: 1, baz: 2}.find_index {|key, value| value > 1 } # => 2
With no argument and no block given, returns an Enumerator.
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 |
# File 'enum.c', line 450
static VALUE
enum_find_index(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo; /* [return value, current index, ] */
VALUE condition_value = Qnil;
rb_block_call_func *func;
if (argc == 0) {
RETURN_ENUMERATOR(obj, 0, 0);
func = find_index_iter_i;
}
else {
rb_scan_args(argc, argv, "1", &condition_value);
if (rb_block_given_p()) {
rb_warn("given block not used");
}
func = find_index_i;
}
memo = MEMO_NEW(Qnil, condition_value, 0);
rb_block_call(obj, id_each, 0, 0, func, (VALUE)memo);
return memo->v1;
}
|
#first ⇒ nil #first(n) ⇒ Array
Returns the first element or elements.
With no argument, returns the first element, or nil
if there is none:
(1..4).first # => 1
%w[a b c].first # => "a"
{foo: 1, bar: 1, baz: 2}.first # => [:foo, 1]
[].first # => nil
With integer argument n
, returns an array containing the first n
elements that exist:
(1..4).first(2) # => [1, 2]
%w[a b c d].first(3) # => ["a", "b", "c"]
%w[a b c d].first(50) # => ["a", "b", "c", "d"]
{foo: 1, bar: 1, baz: 2}.first(2) # => [[:foo, 1], [:bar, 1]]
[].first(2) # => []
1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 |
# File 'enum.c', line 1337
static VALUE
enum_first(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
rb_check_arity(argc, 0, 1);
if (argc > 0) {
return enum_take(obj, argv[0]);
}
else {
memo = MEMO_NEW(Qnil, 0, 0);
rb_block_call(obj, id_each, 0, 0, first_i, (VALUE)memo);
return memo->v1;
}
}
|
#flat_map {|element| ... } ⇒ Array #flat_map ⇒ Object
Returns an array of flattened objects returned by the block.
With a block given, calls the block with successive elements; returns a flattened array of objects returned by the block:
[0, 1, 2, 3].flat_map {|element| -element } # => [0, -1, -2, -3]
[0, 1, 2, 3].flat_map {|element| [element, -element] } # => [0, 0, 1, -1, 2, -2, 3, -3]
[[0, 1], [2, 3]].flat_map {|e| e + [100] } # => [0, 1, 100, 2, 3, 100]
{foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] } # => [:foo, 0, :bar, 1, :baz, 2]
With no block given, returns an Enumerator.
Alias: #collect_concat.
707 708 709 710 711 712 713 714 715 716 717 718 |
# File 'enum.c', line 707
static VALUE
enum_flat_map(VALUE obj)
{
VALUE ary;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, flat_map_i, ary);
return ary;
}
|
#grep(pattern) ⇒ Array #grep(pattern) {|element| ... } ⇒ Array
Returns an array of objects based elements of self
that match the given pattern.
With no block given, returns an array containing each element for which pattern === element
is true
:
a = ['foo', 'bar', 'car', 'moo']
a.grep(/ar/) # => ["bar", "car"]
(1..10).grep(3..8) # => [3, 4, 5, 6, 7, 8]
['a', 'b', 0, 1].grep(Integer) # => [0, 1]
With a block given, calls the block with each matching element and returns an array containing each object returned by the block:
a = ['foo', 'bar', 'car', 'moo']
a.grep(/ar/) {|element| element.upcase } # => ["BAR", "CAR"]
Related: #grep_v.
172 173 174 175 176 |
# File 'enum.c', line 172
static VALUE
enum_grep(VALUE obj, VALUE pat)
{
return enum_grep0(obj, pat, Qtrue);
}
|
#grep_v(pattern) ⇒ Array #grep_v(pattern) {|element| ... } ⇒ Array
Returns an array of objects based on elements of self
that don’t match the given pattern.
With no block given, returns an array containing each element for which pattern === element
is false
:
a = ['foo', 'bar', 'car', 'moo']
a.grep_v(/ar/) # => ["foo", "moo"]
(1..10).grep_v(3..8) # => [1, 2, 9, 10]
['a', 'b', 0, 1].grep_v(Integer) # => ["a", "b"]
With a block given, calls the block with each non-matching element and returns an array containing each object returned by the block:
a = ['foo', 'bar', 'car', 'moo']
a.grep_v(/ar/) {|element| element.upcase } # => ["FOO", "MOO"]
Related: #grep.
204 205 206 207 208 |
# File 'enum.c', line 204
static VALUE
enum_grep_v(VALUE obj, VALUE pat)
{
return enum_grep0(obj, pat, Qfalse);
}
|
#group_by {|element| ... } ⇒ Hash #group_by ⇒ Object
With a block given returns a hash:
-
Each key is a return value from the block.
-
Each value is an array of those elements for which the block returned that key.
Examples:
g = (1..6).group_by {|i| i%3 }
g # => {1=>[1, 4], 2=>[2, 5], 0=>[3, 6]}
h = {foo: 0, bar: 1, baz: 0, bat: 1}
g = h.group_by {|key, value| value }
g # => {0=>[[:foo, 0], [:baz, 0]], 1=>[[:bar, 1], [:bat, 1]]}
With no block given, returns an Enumerator.
1192 1193 1194 1195 1196 1197 1198 |
# File 'enum.c', line 1192
static VALUE
enum_group_by(VALUE obj)
{
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
return enum_hashify(obj, 0, 0, group_by_i);
}
|
#include?(object) ⇒ Boolean
Returns whether for any element object == element
:
(1..4).include?(2) # => true
(1..4).include?(5) # => false
(1..4).include?('2') # => false
%w[a b c d].include?('b') # => true
%w[a b c d].include?('2') # => false
{foo: 0, bar: 1, baz: 2}.include?(:foo) # => true
{foo: 0, bar: 1, baz: 2}.include?('foo') # => false
{foo: 0, bar: 1, baz: 2}.include?(0) # => false
2977 2978 2979 2980 2981 2982 2983 2984 |
# File 'enum.c', line 2977
static VALUE
enum_member(VALUE obj, VALUE val)
{
struct MEMO *memo = MEMO_NEW(val, Qfalse, 0);
rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
return memo->v2;
}
|
#inject(symbol) ⇒ Object #inject(initial_value, symbol) ⇒ Object #inject {|memo, value| ... } ⇒ Object #inject(initial_value) {|memo, value| ... } ⇒ Object
Returns the result of applying a reducer to an initial value and the first element of the Enumerable. It then takes the result and applies the function to it and the second element of the collection, and so on. The return value is the result returned by the final call to the function.
You can think of
[ a, b, c, d ].inject(i) { |r, v| fn(r, v) }
as being
fn(fn(fn(fn(i, a), b), c), d)
In a way the inject
function injects the function between the elements of the enumerable.
inject
is aliased as reduce
. You use it when you want to reduce a collection to a single value.
The Calling Sequences
Let’s start with the most verbose:
enum.inject(initial_value) do |result, next_value|
# do something with +result+ and +next_value+
# the value returned by the block becomes the
# value passed in to the next iteration
# as +result+
end
For example:
product = [ 2, 3, 4 ].inject(1) do |result, next_value|
result * next_value
end
product #=> 24
When this runs, the block is first called with 1
(the initial value) and 2
(the first element of the array). The block returns 1*2
, so on the next iteration the block is called with 2
(the previous result) and 3
. The block returns 6
, and is called one last time with 6
and 4
. The result of the block, 24
becomes the value returned by inject
. This code returns the product of the elements in the enumerable.
First Shortcut: Default Initial value
In the case of the previous example, the initial value, 1
, wasn’t really necessary: the calculation of the product of a list of numbers is self-contained.
In these circumstances, you can omit the initial_value
parameter. inject
will then initially call the block with the first element of the collection as the result
parameter and the second element as the next_value
.
[ 2, 3, 4 ].inject do |result, next_value|
result * next_value
end
This shortcut is convenient, but can only be used when the block produces a result which can be passed back to it as a first parameter.
Here’s an example where that’s not the case: it returns a hash where the keys are words and the values are the number of occurrences of that word in the enumerable.
freqs = File.read("README.md")
.scan(/\w{2,}/)
.reduce(Hash.new(0)) do |counts, word|
counts[word] += 1
counts
end
freqs #=> {"Actions"=>4,
"Status"=>5,
"MinGW"=>3,
"https"=>27,
"github"=>10,
"com"=>15, ...
Note that the last line of the block is just the word counts
. This ensures the return value of the block is the result that’s being calculated.
Second Shortcut: a Reducer function
A reducer function is a function that takes a partial result and the next value, returning the next partial result. The block that is given to inject
is a reducer.
You can also write a reducer as a function and pass the name of that function (as a symbol) to inject
. However, for this to work, the function
-
Must be defined on the type of the result value
-
Must accept a single parameter, the next value in the collection, and
-
Must return an updated result which will also implement the function.
Here’s an example that adds elements to a string. The two calls invoke the functions String#concat and String#+ on the result so far, passing it the next value.
s = [ "cat", " ", "dog" ].inject("", :concat)
s #=> "cat dog"
s = [ "cat", " ", "dog" ].inject("The result is:", :+)
s #=> "The result is: cat dog"
Here’s a more complex example when the result object maintains state of a different type to the enumerable elements.
class Turtle
def initialize
@x = @y = 0
end
def move(dir)
case dir
when "n" then @y += 1
when "s" then @y -= 1
when "e" then @x += 1
when "w" then @x -= 1
end
self
end
end
position = "nnneesw".chars.reduce(Turtle.new, :move)
position #=>> #<Turtle:0x00000001052f4698 @y=2, @x=1>
Third Shortcut: Reducer With no Initial Value
If your reducer returns a value that it can accept as a parameter, then you don’t have to pass in an initial value. Here :*
is the name of the times function:
product = [ 2, 3, 4 ].inject(:*)
product # => 24
String concatenation again:
s = [ "cat", " ", "dog" ].inject(:+)
s #=> "cat dog"
And an example that converts a hash to an array of two-element subarrays.
nested = {foo: 0, bar: 1}.inject([], :push)
nested # => [[:foo, 0], [:bar, 1]]
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
# File 'enum.c', line 1040
static VALUE
enum_inject(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE init, op;
rb_block_call_func *iter = inject_i;
ID id;
int num_args;
if (rb_block_given_p()) {
num_args = rb_scan_args(argc, argv, "02", &init, &op);
}
else {
num_args = rb_scan_args(argc, argv, "11", &init, &op);
}
switch (num_args) {
case 0:
init = Qundef;
break;
case 1:
if (rb_block_given_p()) {
break;
}
id = rb_check_id(&init);
op = id ? ID2SYM(id) : init;
init = Qundef;
iter = inject_op_i;
break;
case 2:
if (rb_block_given_p()) {
rb_warning("given block not used");
}
id = rb_check_id(&op);
if (id) op = ID2SYM(id);
iter = inject_op_i;
break;
}
if (iter == inject_op_i &&
SYMBOL_P(op) &&
RB_TYPE_P(obj, T_ARRAY) &&
rb_method_basic_definition_p(CLASS_OF(obj), id_each)) {
return ary_inject_op(obj, init, op);
}
memo = MEMO_NEW(init, Qnil, op);
rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
if (UNDEF_P(memo->v1)) return Qnil;
return memo->v1;
}
|
#lazy ⇒ Object
Returns an Enumerator::Lazy, which redefines most Enumerable methods to postpone enumeration and enumerate values only on an as-needed basis.
Example
The following program finds pythagorean triples:
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
# show first ten pythagorean triples
p pythagorean_triples.take(10).force # take is lazy, so force is needed
p pythagorean_triples.first(10) # first is eager
# show pythagorean triples less than 100
p pythagorean_triples.take_while { |*, z| z < 100 }.force
1935 1936 1937 1938 1939 1940 1941 1942 |
# File 'enumerator.c', line 1935
static VALUE
enumerable_lazy(VALUE obj)
{
VALUE result = lazy_to_enum_i(obj, sym_each, 0, 0, lazyenum_size, rb_keyword_given_p());
/* Qfalse indicates that the Enumerator::Lazy has no method name */
rb_ivar_set(result, id_method, Qfalse);
return result;
}
|
#map {|element| ... } ⇒ Array #map ⇒ Object
Returns an array of objects returned by the block.
With a block given, calls the block with successive elements; returns an array of the objects returned by the block:
(0..4).map {|i| i*i } # => [0, 1, 4, 9, 16]
{foo: 0, bar: 1, baz: 2}.map {|key, value| value*2} # => [0, 2, 4]
With no block given, returns an Enumerator.
656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
# File 'enum.c', line 656
static VALUE
enum_collect(VALUE obj)
{
VALUE ary;
int min_argc, max_argc;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
min_argc = rb_block_min_max_arity(&max_argc);
rb_lambda_call(obj, id_each, 0, 0, collect_i, min_argc, max_argc, ary);
return ary;
}
|
#max ⇒ Object #max(n) ⇒ Array #max {|a, b| ... } ⇒ Object #max(n) {|a, b| ... } ⇒ Array
Returns the element with the maximum element according to a given criterion. The ordering of equal elements is indeterminate and may be unstable.
With no argument and no block, returns the maximum element, using the elements’ own method #<=>
for comparison:
(1..4).max # => 4
(-4..-1).max # => -1
%w[d c b a].max # => "d"
{foo: 0, bar: 1, baz: 2}.max # => [:foo, 0]
[].max # => nil
With positive integer argument n
given, and no block, returns an array containing the first n
maximum elements that exist:
(1..4).max(2) # => [4, 3]
(-4..-1).max(2) # => [-1, -2]
%w[d c b a].max(2) # => ["d", "c"]
{foo: 0, bar: 1, baz: 2}.max(2) # => [[:foo, 0], [:baz, 2]]
[].max(2) # => []
With a block given, the block determines the maximum elements. The block is called with two elements a
and b
, and must return:
-
A negative integer if
a < b
. -
Zero if
a == b
. -
A positive integer if
a > b
.
With a block given and no argument, returns the maximum element as determined by the block:
%w[xxx x xxxx xx].max {|a, b| a.size <=> b.size } # => "xxxx"
h = {foo: 0, bar: 1, baz: 2}
h.max {|pair1, pair2| pair1[1] <=> pair2[1] } # => [:baz, 2]
[].max {|a, b| a <=> b } # => nil
With a block given and positive integer argument n
given, returns an array containing the first n
maximum elements that exist, as determined by the block.
%w[xxx x xxxx xx].max(2) {|a, b| a.size <=> b.size } # => ["xxxx", "xxx"]
h = {foo: 0, bar: 1, baz: 2}
h.max(2) {|pair1, pair2| pair1[1] <=> pair2[1] }
# => [[:baz, 2], [:bar, 1]]
[].max(2) {|a, b| a <=> b } # => []
Related: #min, #minmax, #max_by.
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 |
# File 'enum.c', line 2498
static VALUE
enum_max(int argc, VALUE *argv, VALUE obj)
{
VALUE memo;
struct max_t *m = NEW_MEMO_FOR(struct max_t, memo);
VALUE result;
VALUE num;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 0, 1, 0);
m->max = Qundef;
if (rb_block_given_p()) {
rb_block_call(obj, id_each, 0, 0, max_ii, (VALUE)memo);
}
else {
rb_block_call(obj, id_each, 0, 0, max_i, (VALUE)memo);
}
result = m->max;
if (UNDEF_P(result)) return Qnil;
return result;
}
|
#max_by {|element| ... } ⇒ Object #max_by(n) {|element| ... } ⇒ Array #max_by ⇒ Object #max_by(n) ⇒ Object
Returns the elements for which the block returns the maximum values.
With a block given and no argument, returns the element for which the block returns the maximum value:
(1..4).max_by {|element| -element } # => 1
%w[a b c d].max_by {|element| -element.ord } # => "a"
{foo: 0, bar: 1, baz: 2}.max_by {|key, value| -value } # => [:foo, 0]
[].max_by {|element| -element } # => nil
With a block given and positive integer argument n
given, returns an array containing the n
elements for which the block returns maximum values:
(1..4).max_by(2) {|element| -element }
# => [1, 2]
%w[a b c d].max_by(2) {|element| -element.ord }
# => ["a", "b"]
{foo: 0, bar: 1, baz: 2}.max_by(2) {|key, value| -value }
# => [[:foo, 0], [:bar, 1]]
[].max_by(2) {|element| -element }
# => []
Returns an Enumerator if no block is given.
Related: #max, #minmax, #min_by.
2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 |
# File 'enum.c', line 2816
static VALUE
enum_max_by(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE num;
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 1, 0);
memo = MEMO_NEW(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, max_by_i, (VALUE)memo);
return memo->v2;
}
|
#include?(object) ⇒ Boolean
Returns whether for any element object == element
:
(1..4).include?(2) # => true
(1..4).include?(5) # => false
(1..4).include?('2') # => false
%w[a b c d].include?('b') # => true
%w[a b c d].include?('2') # => false
{foo: 0, bar: 1, baz: 2}.include?(:foo) # => true
{foo: 0, bar: 1, baz: 2}.include?('foo') # => false
{foo: 0, bar: 1, baz: 2}.include?(0) # => false
2977 2978 2979 2980 2981 2982 2983 2984 |
# File 'enum.c', line 2977
static VALUE
enum_member(VALUE obj, VALUE val)
{
struct MEMO *memo = MEMO_NEW(val, Qfalse, 0);
rb_block_call(obj, id_each, 0, 0, member_i, (VALUE)memo);
return memo->v2;
}
|
#min ⇒ Object #min(n) ⇒ Array #min {|a, b| ... } ⇒ Object #min(n) {|a, b| ... } ⇒ Array
Returns the element with the minimum element according to a given criterion. The ordering of equal elements is indeterminate and may be unstable.
With no argument and no block, returns the minimum element, using the elements’ own method #<=>
for comparison:
(1..4).min # => 1
(-4..-1).min # => -4
%w[d c b a].min # => "a"
{foo: 0, bar: 1, baz: 2}.min # => [:bar, 1]
[].min # => nil
With positive integer argument n
given, and no block, returns an array containing the first n
minimum elements that exist:
(1..4).min(2) # => [1, 2]
(-4..-1).min(2) # => [-4, -3]
%w[d c b a].min(2) # => ["a", "b"]
{foo: 0, bar: 1, baz: 2}.min(2) # => [[:bar, 1], [:baz, 2]]
[].min(2) # => []
With a block given, the block determines the minimum elements. The block is called with two elements a
and b
, and must return:
-
A negative integer if
a < b
. -
Zero if
a == b
. -
A positive integer if
a > b
.
With a block given and no argument, returns the minimum element as determined by the block:
%w[xxx x xxxx xx].min {|a, b| a.size <=> b.size } # => "x"
h = {foo: 0, bar: 1, baz: 2}
h.min {|pair1, pair2| pair1[1] <=> pair2[1] } # => [:foo, 0]
[].min {|a, b| a <=> b } # => nil
With a block given and positive integer argument n
given, returns an array containing the first n
minimum elements that exist, as determined by the block.
%w[xxx x xxxx xx].min(2) {|a, b| a.size <=> b.size } # => ["x", "xx"]
h = {foo: 0, bar: 1, baz: 2}
h.min(2) {|pair1, pair2| pair1[1] <=> pair2[1] }
# => [[:foo, 0], [:bar, 1]]
[].min(2) {|a, b| a <=> b } # => []
Related: #min_by, #minmax, #max.
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 |
# File 'enum.c', line 2376
static VALUE
enum_min(int argc, VALUE *argv, VALUE obj)
{
VALUE memo;
struct min_t *m = NEW_MEMO_FOR(struct min_t, memo);
VALUE result;
VALUE num;
if (rb_check_arity(argc, 0, 1) && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 0, 0, 0);
m->min = Qundef;
if (rb_block_given_p()) {
rb_block_call(obj, id_each, 0, 0, min_ii, memo);
}
else {
rb_block_call(obj, id_each, 0, 0, min_i, memo);
}
result = m->min;
if (UNDEF_P(result)) return Qnil;
return result;
}
|
#min_by {|element| ... } ⇒ Object #min_by(n) {|element| ... } ⇒ Array #min_by ⇒ Object #min_by(n) ⇒ Object
Returns the elements for which the block returns the minimum values.
With a block given and no argument, returns the element for which the block returns the minimum value:
(1..4).min_by {|element| -element } # => 4
%w[a b c d].min_by {|element| -element.ord } # => "d"
{foo: 0, bar: 1, baz: 2}.min_by {|key, value| -value } # => [:baz, 2]
[].min_by {|element| -element } # => nil
With a block given and positive integer argument n
given, returns an array containing the n
elements for which the block returns minimum values:
(1..4).min_by(2) {|element| -element }
# => [4, 3]
%w[a b c d].min_by(2) {|element| -element.ord }
# => ["d", "c"]
{foo: 0, bar: 1, baz: 2}.min_by(2) {|key, value| -value }
# => [[:baz, 2], [:bar, 1]]
[].min_by(2) {|element| -element }
# => []
Returns an Enumerator if no block is given.
Related: #min, #minmax, #max_by.
2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 |
# File 'enum.c', line 2742
static VALUE
enum_min_by(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE num;
rb_check_arity(argc, 0, 1);
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
if (argc && !NIL_P(num = argv[0]))
return rb_nmin_run(obj, num, 1, 0, 0);
memo = MEMO_NEW(Qundef, Qnil, 0);
rb_block_call(obj, id_each, 0, 0, min_by_i, (VALUE)memo);
return memo->v2;
}
|
#minmax ⇒ Array #minmax {|a, b| ... } ⇒ Array
Returns a 2-element array containing the minimum and maximum elements according to a given criterion. The ordering of equal elements is indeterminate and may be unstable.
With no argument and no block, returns the minimum and maximum elements, using the elements’ own method #<=>
for comparison:
(1..4).minmax # => [1, 4]
(-4..-1).minmax # => [-4, -1]
%w[d c b a].minmax # => ["a", "d"]
{foo: 0, bar: 1, baz: 2}.minmax # => [[:bar, 1], [:foo, 0]]
[].minmax # => [nil, nil]
With a block given, returns the minimum and maximum elements as determined by the block:
%w[xxx x xxxx xx].minmax {|a, b| a.size <=> b.size } # => ["x", "xxxx"]
h = {foo: 0, bar: 1, baz: 2}
h.minmax {|pair1, pair2| pair1[1] <=> pair2[1] }
# => [[:foo, 0], [:baz, 2]]
[].minmax {|a, b| a <=> b } # => [nil, nil]
Related: #min, #max, #minmax_by.
2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 |
# File 'enum.c', line 2662
static VALUE
enum_minmax(VALUE obj)
{
VALUE memo;
struct minmax_t *m = NEW_MEMO_FOR(struct minmax_t, memo);
m->min = Qundef;
m->last = Qundef;
if (rb_block_given_p()) {
rb_block_call(obj, id_each, 0, 0, minmax_ii, memo);
if (!UNDEF_P(m->last))
minmax_ii_update(m->last, m->last, m);
}
else {
rb_block_call(obj, id_each, 0, 0, minmax_i, memo);
if (!UNDEF_P(m->last))
minmax_i_update(m->last, m->last, m);
}
if (!UNDEF_P(m->min)) {
return rb_assoc_new(m->min, m->max);
}
return rb_assoc_new(Qnil, Qnil);
}
|
#minmax_by {|element| ... } ⇒ Array #minmax_by ⇒ Object
Returns a 2-element array containing the elements for which the block returns minimum and maximum values:
(1..4).minmax_by {|element| -element }
# => [4, 1]
%w[a b c d].minmax_by {|element| -element.ord }
# => ["d", "a"]
{foo: 0, bar: 1, baz: 2}.minmax_by {|key, value| -value }
# => [[:baz, 2], [:foo, 0]]
[].minmax_by {|element| -element }
# => [nil, nil]
Returns an Enumerator if no block is given.
Related: #max_by, #minmax, #min_by.
2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 |
# File 'enum.c', line 2927
static VALUE
enum_minmax_by(VALUE obj)
{
VALUE memo;
struct minmax_by_t *m = NEW_MEMO_FOR(struct minmax_by_t, memo);
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
m->min_bv = Qundef;
m->max_bv = Qundef;
m->min = Qnil;
m->max = Qnil;
m->last_bv = Qundef;
m->last = Qundef;
rb_block_call(obj, id_each, 0, 0, minmax_by_i, memo);
if (!UNDEF_P(m->last_bv))
minmax_by_i_update(m->last_bv, m->last_bv, m->last, m->last, m);
m = MEMO_FOR(struct minmax_by_t, memo);
return rb_assoc_new(m->min, m->max);
}
|
#none? ⇒ Boolean #none?(pattern) ⇒ Boolean #none? {|element| ... } ⇒ Boolean
Returns whether no element meets a given criterion.
With no argument and no block, returns whether no element is truthy:
(1..4).none? # => false
[nil, false].none? # => true
{foo: 0}.none? # => false
{foo: 0, bar: 1}.none? # => false
[].none? # => true
With argument pattern
and no block, returns whether for no element element
, pattern === element
:
[nil, false, 1.1].none?(Integer) # => true
%w[bar baz bat bam].none?(/m/) # => false
%w[bar baz bat bam].none?(/foo/) # => true
%w[bar baz bat bam].none?('ba') # => true
{foo: 0, bar: 1, baz: 2}.none?(Hash) # => true
{foo: 0}.none?(Array) # => false
[].none?(Integer) # => true
With a block given, returns whether the block returns a truthy value for no element:
(1..4).none? {|element| element < 1 } # => true
(1..4).none? {|element| element < 2 } # => false
{foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 0 } # => true
{foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 1 } # => false
Related: #one?, #all?, #any?.
2266 2267 2268 2269 2270 2271 2272 2273 2274 |
# File 'enum.c', line 2266
static VALUE
enum_none(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qtrue);
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(none);
return memo->v1;
}
|
#one? ⇒ Boolean #one?(pattern) ⇒ Boolean #one? {|element| ... } ⇒ Boolean
Returns whether exactly one element meets a given criterion.
With no argument and no block, returns whether exactly one element is truthy:
(1..1).one? # => true
[1, nil, false].one? # => true
(1..4).one? # => false
{foo: 0}.one? # => true
{foo: 0, bar: 1}.one? # => false
[].one? # => false
With argument pattern
and no block, returns whether for exactly one element element
, pattern === element
:
[nil, false, 0].one?(Integer) # => true
[nil, false, 0].one?(Numeric) # => true
[nil, false, 0].one?(Float) # => false
%w[bar baz bat bam].one?(/m/) # => true
%w[bar baz bat bam].one?(/foo/) # => false
%w[bar baz bat bam].one?('ba') # => false
{foo: 0, bar: 1, baz: 2}.one?(Array) # => false
{foo: 0}.one?(Array) # => true
[].one?(Integer) # => false
With a block given, returns whether the block returns a truthy value for exactly one element:
(1..4).one? {|element| element < 2 } # => true
(1..4).one? {|element| element < 1 } # => false
{foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 1 } # => true
{foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 2 } # => false
Related: #none?, #all?, #any?.
2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 |
# File 'enum.c', line 2204
static VALUE
enum_one(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo = MEMO_ENUM_NEW(Qundef);
VALUE result;
WARN_UNUSED_BLOCK(argc);
ENUM_BLOCK_CALL(one);
result = memo->v1;
if (UNDEF_P(result)) return Qfalse;
return result;
}
|
#partition {|element| ... } ⇒ Array #partition ⇒ Object
With a block given, returns an array of two arrays:
-
The first having those elements for which the block returns a truthy value.
-
The other having all other elements.
Examples:
p = (1..4).partition {|i| i.even? }
p # => [[2, 4], [1, 3]]
p = ('a'..'d').partition {|c| c < 'c' }
p # => [["a", "b"], ["c", "d"]]
h = {foo: 0, bar: 1, baz: 2, bat: 3}
p = h.partition {|key, value| key.start_with?('b') }
p # => [[[:bar, 1], [:baz, 2], [:bat, 3]], [[:foo, 0]]]
p = h.partition {|key, value| value < 2 }
p # => [[[:foo, 0], [:bar, 1]], [[:baz, 2], [:bat, 3]]]
With no block given, returns an Enumerator.
Related: Enumerable#group_by.
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 |
# File 'enum.c', line 1137
static VALUE
enum_partition(VALUE obj)
{
struct MEMO *memo;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
memo = MEMO_NEW(rb_ary_new(), rb_ary_new(), 0);
rb_block_call(obj, id_each, 0, 0, partition_i, (VALUE)memo);
return rb_assoc_new(memo->v1, memo->v2);
}
|
#inject(symbol) ⇒ Object #inject(initial_value, symbol) ⇒ Object #inject {|memo, value| ... } ⇒ Object #inject(initial_value) {|memo, value| ... } ⇒ Object
Returns the result of applying a reducer to an initial value and the first element of the Enumerable. It then takes the result and applies the function to it and the second element of the collection, and so on. The return value is the result returned by the final call to the function.
You can think of
[ a, b, c, d ].inject(i) { |r, v| fn(r, v) }
as being
fn(fn(fn(fn(i, a), b), c), d)
In a way the inject
function injects the function between the elements of the enumerable.
inject
is aliased as reduce
. You use it when you want to reduce a collection to a single value.
The Calling Sequences
Let’s start with the most verbose:
enum.inject(initial_value) do |result, next_value|
# do something with +result+ and +next_value+
# the value returned by the block becomes the
# value passed in to the next iteration
# as +result+
end
For example:
product = [ 2, 3, 4 ].inject(1) do |result, next_value|
result * next_value
end
product #=> 24
When this runs, the block is first called with 1
(the initial value) and 2
(the first element of the array). The block returns 1*2
, so on the next iteration the block is called with 2
(the previous result) and 3
. The block returns 6
, and is called one last time with 6
and 4
. The result of the block, 24
becomes the value returned by inject
. This code returns the product of the elements in the enumerable.
First Shortcut: Default Initial value
In the case of the previous example, the initial value, 1
, wasn’t really necessary: the calculation of the product of a list of numbers is self-contained.
In these circumstances, you can omit the initial_value
parameter. inject
will then initially call the block with the first element of the collection as the result
parameter and the second element as the next_value
.
[ 2, 3, 4 ].inject do |result, next_value|
result * next_value
end
This shortcut is convenient, but can only be used when the block produces a result which can be passed back to it as a first parameter.
Here’s an example where that’s not the case: it returns a hash where the keys are words and the values are the number of occurrences of that word in the enumerable.
freqs = File.read("README.md")
.scan(/\w{2,}/)
.reduce(Hash.new(0)) do |counts, word|
counts[word] += 1
counts
end
freqs #=> {"Actions"=>4,
"Status"=>5,
"MinGW"=>3,
"https"=>27,
"github"=>10,
"com"=>15, ...
Note that the last line of the block is just the word counts
. This ensures the return value of the block is the result that’s being calculated.
Second Shortcut: a Reducer function
A reducer function is a function that takes a partial result and the next value, returning the next partial result. The block that is given to inject
is a reducer.
You can also write a reducer as a function and pass the name of that function (as a symbol) to inject
. However, for this to work, the function
-
Must be defined on the type of the result value
-
Must accept a single parameter, the next value in the collection, and
-
Must return an updated result which will also implement the function.
Here’s an example that adds elements to a string. The two calls invoke the functions String#concat and String#+ on the result so far, passing it the next value.
s = [ "cat", " ", "dog" ].inject("", :concat)
s #=> "cat dog"
s = [ "cat", " ", "dog" ].inject("The result is:", :+)
s #=> "The result is: cat dog"
Here’s a more complex example when the result object maintains state of a different type to the enumerable elements.
class Turtle
def initialize
@x = @y = 0
end
def move(dir)
case dir
when "n" then @y += 1
when "s" then @y -= 1
when "e" then @x += 1
when "w" then @x -= 1
end
self
end
end
position = "nnneesw".chars.reduce(Turtle.new, :move)
position #=>> #<Turtle:0x00000001052f4698 @y=2, @x=1>
Third Shortcut: Reducer With no Initial Value
If your reducer returns a value that it can accept as a parameter, then you don’t have to pass in an initial value. Here :*
is the name of the times function:
product = [ 2, 3, 4 ].inject(:*)
product # => 24
String concatenation again:
s = [ "cat", " ", "dog" ].inject(:+)
s #=> "cat dog"
And an example that converts a hash to an array of two-element subarrays.
nested = {foo: 0, bar: 1}.inject([], :push)
nested # => [[:foo, 0], [:bar, 1]]
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
# File 'enum.c', line 1040
static VALUE
enum_inject(int argc, VALUE *argv, VALUE obj)
{
struct MEMO *memo;
VALUE init, op;
rb_block_call_func *iter = inject_i;
ID id;
int num_args;
if (rb_block_given_p()) {
num_args = rb_scan_args(argc, argv, "02", &init, &op);
}
else {
num_args = rb_scan_args(argc, argv, "11", &init, &op);
}
switch (num_args) {
case 0:
init = Qundef;
break;
case 1:
if (rb_block_given_p()) {
break;
}
id = rb_check_id(&init);
op = id ? ID2SYM(id) : init;
init = Qundef;
iter = inject_op_i;
break;
case 2:
if (rb_block_given_p()) {
rb_warning("given block not used");
}
id = rb_check_id(&op);
if (id) op = ID2SYM(id);
iter = inject_op_i;
break;
}
if (iter == inject_op_i &&
SYMBOL_P(op) &&
RB_TYPE_P(obj, T_ARRAY) &&
rb_method_basic_definition_p(CLASS_OF(obj), id_each)) {
return ary_inject_op(obj, init, op);
}
memo = MEMO_NEW(init, Qnil, op);
rb_block_call(obj, id_each, 0, 0, iter, (VALUE)memo);
if (UNDEF_P(memo->v1)) return Qnil;
return memo->v1;
}
|
#reject {|element| ... } ⇒ Array #reject ⇒ Object
Returns an array of objects rejected by the block.
With a block given, calls the block with successive elements; returns an array of those elements for which the block returns nil
or false
:
(0..9).reject {|i| i * 2 if i.even? } # => [1, 3, 5, 7, 9]
{foo: 0, bar: 1, baz: 2}.reject {|key, value| key if value.odd? } # => {:foo=>0, :baz=>2}
When no block given, returns an Enumerator.
Related: #select.
611 612 613 614 615 616 617 618 619 620 621 622 |
# File 'enum.c', line 611
static VALUE
enum_reject(VALUE obj)
{
VALUE ary;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, reject_i, ary);
return ary;
}
|
#reverse_each(*args) {|element| ... } ⇒ self #reverse_each(*args) ⇒ Object
With a block given, calls the block with each element, but in reverse order; returns self
:
a = []
(1..4).reverse_each {|element| a.push(-element) } # => 1..4
a # => [-4, -3, -2, -1]
a = []
%w[a b c d].reverse_each {|element| a.push(element) }
# => ["a", "b", "c", "d"]
a # => ["d", "c", "b", "a"]
a = []
h.reverse_each {|element| a.push(element) }
# => {:foo=>0, :bar=>1, :baz=>2}
a # => [[:baz, 2], [:bar, 1], [:foo, 0]]
With no block given, returns an Enumerator.
3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 |
# File 'enum.c', line 3059
static VALUE
enum_reverse_each(int argc, VALUE *argv, VALUE obj)
{
VALUE ary;
long len;
RETURN_SIZED_ENUMERATOR(obj, argc, argv, enum_size);
ary = enum_to_a(argc, argv, obj);
len = RARRAY_LEN(ary);
while (len--) {
long nlen;
rb_yield(RARRAY_AREF(ary, len));
nlen = RARRAY_LEN(ary);
if (nlen < len) {
len = nlen;
}
}
return obj;
}
|
#select {|element| ... } ⇒ Array #select ⇒ Object
Returns an array containing elements selected by the block.
With a block given, calls the block with successive elements; returns an array of those elements for which the block returns a truthy value:
(0..9).select {|element| element % 3 == 0 } # => [0, 3, 6, 9]
a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') }
a # => {:bar=>1, :baz=>2}
With no block given, returns an Enumerator.
Related: #reject.
527 528 529 530 531 532 533 534 535 536 537 538 |
# File 'enum.c', line 527
static VALUE
enum_find_all(VALUE obj)
{
VALUE ary;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, find_all_i, ary);
return ary;
}
|
#slice_after(pattern) ⇒ Object #slice_after {|elt| ... } ⇒ Object
Creates an enumerator for each chunked elements. The ends of chunks are defined by pattern and the block.
If pattern === elt
returns true
or the block returns true
for the element, the element is end of a chunk.
The ===
and block is called from the first element to the last element of enum.
The result enumerator yields the chunked elements as an array. So each
method can be called as follows:
enum.slice_after(pattern).each { |ary| ... }
enum.slice_after { |elt| bool }.each { |ary| ... }
Other methods of the Enumerator class and Enumerable module, such as map
, etc., are also usable.
For example, continuation lines (lines end with backslash) can be concatenated as follows:
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"]
4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 |
# File 'enum.c', line 4344
static VALUE
enum_slice_after(int argc, VALUE *argv, VALUE enumerable)
{
VALUE enumerator;
VALUE pat = Qnil, pred = Qnil;
if (rb_block_given_p()) {
if (0 < argc)
rb_raise(rb_eArgError, "both pattern and block are given");
pred = rb_block_proc();
}
else {
rb_scan_args(argc, argv, "1", &pat);
}
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_sliceafter_enum, enumerable);
rb_ivar_set(enumerator, id_sliceafter_pat, pat);
rb_ivar_set(enumerator, id_sliceafter_pred, pred);
rb_block_call(enumerator, idInitialize, 0, 0, sliceafter_i, enumerator);
return enumerator;
}
|
#slice_before(pattern) ⇒ Object #slice_before {|elt| ... } ⇒ Object
With argument pattern
, returns an enumerator that uses the pattern to partition elements into arrays (“slices”). An element begins a new slice if element === pattern
(or if it is the first element).
a = %w[foo bar fop for baz fob fog bam foy]
e = a.slice_before(/ba/) # => #<Enumerator: ...>
e.each {|array| p array }
Output:
["foo"]
["bar", "fop", "for"]
["baz", "fob", "fog"]
["bam", "foy"]
With a block, returns an enumerator that uses the block to partition elements into arrays. An element begins a new slice if its block return is a truthy value (or if it is the first element):
e = (1..20).slice_before {|i| i % 4 == 2 } # => #<Enumerator: ...>
e.each {|array| p array }
Output:
[1]
[2, 3, 4, 5]
[6, 7, 8, 9]
[10, 11, 12, 13]
[14, 15, 16, 17]
[18, 19, 20]
Other methods of the Enumerator class and Enumerable module, such as to_a
, map
, etc., are also usable.
For example, iteration over ChangeLog entries can be implemented as follows:
# iterate over ChangeLog entries.
open("ChangeLog") { |f|
f.slice_before(/\A\S/).each { |e| pp e }
}
# same as above. block is used instead of pattern argument.
open("ChangeLog") { |f|
f.slice_before { |line| /\A\S/ === line }.each { |e| pp e }
}
“svn proplist -R” produces multiline output for each file. They can be chunked as follows:
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"]
# ...
If the block needs to maintain state over multiple elements, local variables can be used. For example, three or more consecutive increasing numbers can be squashed as follows (see chunk_while
for a better way):
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"
However local variables should be used carefully if the result enumerator is enumerated twice or more. The local variables should be initialized for each enumeration. Enumerator.new can be used to do it.
# Word wrapping. This assumes all characters have same width.
def wordwrap(words, maxwidth)
Enumerator.new {|y|
# cols is initialized in Enumerator.new.
cols = 0
words.slice_before { |w|
cols += 1 if cols != 0
cols += w.length
if maxwidth < cols
cols = w.length
true
else
false
end
}.each {|ws| y.yield ws }
}
end
text = (1..20).to_a.join(" ")
enum = wordwrap(text.split(/\s+/), 10)
puts "-"*10
enum.each { |ws| puts ws.join(" ") } # first enumeration.
puts "-"*10
enum.each { |ws| puts ws.join(" ") } # second enumeration generates same result as the first.
puts "-"*10
#=> ----------
# 1 2 3 4 5
# 6 7 8 9 10
# 11 12 13
# 14 15 16
# 17 18 19
# 20
# ----------
# 1 2 3 4 5
# 6 7 8 9 10
# 11 12 13
# 14 15 16
# 17 18 19
# 20
# ----------
mbox contains series of mails which start with Unix From line. So each mail can be extracted by slice before Unix From line.
# parse mbox
open("mbox") { |f|
f.slice_before { |line|
line.start_with? "From "
}.each { |mail|
unix_from = mail.shift
i = mail.index("\n")
header = mail[0...i]
body = mail[(i+1)..-1]
body.pop if body.last == "\n"
fields = header.slice_before { |line| !" \t".include?(line[0]) }.to_a
p unix_from
pp fields
pp body
}
}
# split mails in mbox (slice before Unix From line after an empty line)
open("mbox") { |f|
emp = true
f.slice_before { |line|
prevemp = emp
emp = line == "\n"
prevemp && line.start_with?("From ")
}.each { |mail|
mail.pop if mail.last == "\n"
pp mail
}
}
4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 |
# File 'enum.c', line 4222
static VALUE
enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
{
VALUE enumerator;
if (rb_block_given_p()) {
if (argc != 0)
rb_error_arity(argc, 0, 0);
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicebefore_sep_pred, rb_block_proc());
}
else {
VALUE sep_pat;
rb_scan_args(argc, argv, "1", &sep_pat);
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicebefore_sep_pat, sep_pat);
}
rb_ivar_set(enumerator, id_slicebefore_enumerable, enumerable);
rb_block_call(enumerator, idInitialize, 0, 0, slicebefore_i, enumerator);
return enumerator;
}
|
#slice_when {|elt_before, elt_after| ... } ⇒ Object
Creates an enumerator for each chunked elements. The beginnings of chunks are defined by the block.
This method splits each chunk using adjacent elements, elt_before and elt_after, in the receiver enumerator. This method split chunks between elt_before and elt_after where the block returns true
.
The block is called the length of the receiver enumerator minus one.
The result enumerator yields the chunked elements as an array. So each
method can be called as follows:
enum.slice_when { |elt_before, elt_after| bool }.each { |ary| ... }
Other methods of the Enumerator class and Enumerable module, such as to_a
, map
, etc., are also usable.
For example, one-by-one increasing subsequence can be chunked as follows:
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"
Near elements (threshold: 6) in sorted array can be chunked as follows:
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]]
Increasing (non-decreasing) subsequence can be chunked as follows:
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]]
Adjacent evens and odds can be chunked as follows: (Enumerable#chunk is another way to do it.)
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]]
Paragraphs (non-empty lines with trailing empty lines) can be chunked as follows: (See Enumerable#chunk to ignore empty lines.)
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 does the same, except splitting when the block returns false
instead of true
.
4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 |
# File 'enum.c', line 4501
static VALUE
enum_slice_when(VALUE enumerable)
{
VALUE enumerator;
VALUE pred;
pred = rb_block_proc();
enumerator = rb_obj_alloc(rb_cEnumerator);
rb_ivar_set(enumerator, id_slicewhen_enum, enumerable);
rb_ivar_set(enumerator, id_slicewhen_pred, pred);
rb_ivar_set(enumerator, id_slicewhen_inverted, Qfalse);
rb_block_call(enumerator, idInitialize, 0, 0, slicewhen_i, enumerator);
return enumerator;
}
|
#sort ⇒ Array #sort {|a, b| ... } ⇒ Array
Returns an array containing the sorted elements of self
. The ordering of equal elements is indeterminate and may be unstable.
With no block given, the sort compares using the elements’ own method #<=>
:
%w[b c a d].sort # => ["a", "b", "c", "d"]
{foo: 0, bar: 1, baz: 2}.sort # => [[:bar, 1], [:baz, 2], [:foo, 0]]
With a block given, comparisons in the block determine the ordering. The block is called with two elements a
and b
, and must return:
-
A negative integer if
a < b
. -
Zero if
a == b
. -
A positive integer if
a > b
.
Examples:
a = %w[b c a d]
a.sort {|a, b| b <=> a } # => ["d", "c", "b", "a"]
h = {foo: 0, bar: 1, baz: 2}
h.sort {|a, b| b <=> a } # => [[:foo, 0], [:baz, 2], [:bar, 1]]
See also #sort_by. It implements a Schwartzian transform which is useful when key computation or comparison is expensive.
1384 1385 1386 1387 1388 |
# File 'enum.c', line 1384
static VALUE
enum_sort(VALUE obj)
{
return rb_ary_sort_bang(enum_to_a(0, 0, obj));
}
|
#sort_by {|element| ... } ⇒ Array #sort_by ⇒ Object
With a block given, returns an array of elements of self
, sorted according to the value returned by the block for each element. The ordering of equal elements is indeterminate and may be unstable.
Examples:
a = %w[xx xxx x xxxx]
a.sort_by {|s| s.size } # => ["x", "xx", "xxx", "xxxx"]
a.sort_by {|s| -s.size } # => ["xxxx", "xxx", "xx", "x"]
h = {foo: 2, bar: 1, baz: 0}
h.sort_by{|key, value| value } # => [[:baz, 0], [:bar, 1], [:foo, 2]]
h.sort_by{|key, value| key } # => [[:bar, 1], [:baz, 0], [:foo, 2]]
With no block given, returns an Enumerator.
The current implementation of #sort_by generates an array of tuples containing the original collection element and the mapped value. This makes #sort_by fairly expensive when the keysets are simple.
require 'benchmark'
a = (1..100000).map { rand(100000) }
Benchmark.bm(10) do |b|
b.report("Sort") { a.sort }
b.report("Sort by") { a.sort_by { |a| a } }
end
produces:
user system total real
Sort 0.180000 0.000000 0.180000 ( 0.175469)
Sort by 1.980000 0.040000 2.020000 ( 2.013586)
However, consider the case where comparing the keys is a non-trivial operation. The following code sorts some files on modification time using the basic #sort method.
files = Dir["*"]
sorted = files.sort { |a, b| File.new(a).mtime <=> File.new(b).mtime }
sorted #=> ["mon", "tues", "wed", "thurs"]
This sort is inefficient: it generates two new File objects during every comparison. A slightly better technique is to use the Kernel#test method to generate the modification times directly.
files = Dir["*"]
sorted = files.sort { |a, b|
test(?M, a) <=> test(?M, b)
}
sorted #=> ["mon", "tues", "wed", "thurs"]
This still generates many unnecessary Time objects. A more efficient technique is to cache the sort keys (modification times in this case) before the sort. Perl users often call this approach a Schwartzian transform, after Randal Schwartz. We construct a temporary array, where each element is an array containing our sort key along with the filename. We sort this array, and then extract the filename from the result.
sorted = Dir["*"].collect { |f|
[test(?M, f), f]
}.sort.collect { |f| f[1] }
sorted #=> ["mon", "tues", "wed", "thurs"]
This is exactly what #sort_by does internally.
sorted = Dir["*"].sort_by { |f| test(?M, f) }
sorted #=> ["mon", "tues", "wed", "thurs"]
To produce the reverse of a specific order, the following can be used:
ary.sort_by { ... }.reverse!
1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 |
# File 'enum.c', line 1704
static VALUE
enum_sort_by(VALUE obj)
{
VALUE ary, buf;
struct MEMO *memo;
long i;
struct sort_by_data *data;
RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);
if (RB_TYPE_P(obj, T_ARRAY) && RARRAY_LEN(obj) <= LONG_MAX/2) {
ary = rb_ary_new2(RARRAY_LEN(obj)*2);
}
else {
ary = rb_ary_new();
}
RBASIC_CLEAR_CLASS(ary);
buf = rb_ary_hidden_new(SORT_BY_BUFSIZE*2);
rb_ary_store(buf, SORT_BY_BUFSIZE*2-1, Qnil);
memo = MEMO_NEW(0, 0, 0);
data = (struct sort_by_data *)&memo->v1;
RB_OBJ_WRITE(memo, &data->ary, ary);
RB_OBJ_WRITE(memo, &data->buf, buf);
data->n = 0;
data->primitive_uniformed = SORT_BY_UNIFORMED((CMP_OPTIMIZABLE(FLOAT) && CMP_OPTIMIZABLE(INTEGER)),
CMP_OPTIMIZABLE(FLOAT),
CMP_OPTIMIZABLE(INTEGER));
rb_block_call(obj, id_each, 0, 0, sort_by_i, (VALUE)memo);
ary = data->ary;
buf = data->buf;
if (data->n) {
rb_ary_resize(buf, data->n*2);
rb_ary_concat(ary, buf);
}
if (RARRAY_LEN(ary) > 2) {
if (data->primitive_uniformed) {
RARRAY_PTR_USE(ary, ptr,
rb_uniform_intro_sort_2((struct rb_uniform_sort_data*)ptr,
(struct rb_uniform_sort_data*)(ptr + RARRAY_LEN(ary))));
}
else {
RARRAY_PTR_USE(ary, ptr,
ruby_qsort(ptr, RARRAY_LEN(ary)/2, 2*sizeof(VALUE),
sort_by_cmp, (void *)ary));
}
}
if (RBASIC(ary)->klass) {
rb_raise(rb_eRuntimeError, "sort_by reentered");
}
for (i=1; i<RARRAY_LEN(ary); i+=2) {
RARRAY_ASET(ary, i/2, RARRAY_AREF(ary, i));
}
rb_ary_resize(ary, RARRAY_LEN(ary)/2);
RBASIC_SET_CLASS_RAW(ary, rb_cArray);
return ary;
}
|
#sum(initial_value = 0) ⇒ Numeric #sum(initial_value = 0) {|element| ... } ⇒ Object
With no block given, returns the sum of initial_value
and the elements:
(1..100).sum # => 5050
(1..100).sum(1) # => 5051
('a'..'d').sum('foo') # => "fooabcd"
Generally, the sum is computed using methods +
and each
; for performance optimizations, those methods may not be used, and so any redefinition of those methods may not have effect here.
One such optimization: When possible, computes using Gauss’s summation formula n(n+1)/2:
100 * (100 + 1) / 2 # => 5050
With a block given, calls the block with each element; returns the sum of initial_value
and the block return values:
(1..4).sum {|i| i*i } # => 30
(1..4).sum(100) {|i| i*i } # => 130
h = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5}
h.sum {|key, value| value.odd? ? value : 0 } # => 9
('a'..'f').sum('x') {|c| c < 'd' ? c : '' } # => "xabc"
4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 |
# File 'enum.c', line 4806
static VALUE
enum_sum(int argc, VALUE* argv, VALUE obj)
{
struct enum_sum_memo memo;
VALUE beg, end;
int excl;
memo.v = (rb_check_arity(argc, 0, 1) == 0) ? LONG2FIX(0) : argv[0];
memo.block_given = rb_block_given_p();
memo.n = 0;
memo.r = Qundef;
if ((memo.float_value = RB_FLOAT_TYPE_P(memo.v))) {
memo.f = RFLOAT_VALUE(memo.v);
memo.c = 0.0;
}
else {
memo.f = 0.0;
memo.c = 0.0;
}
if (RTEST(rb_range_values(obj, &beg, &end, &excl))) {
if (!memo.block_given && !memo.float_value &&
(FIXNUM_P(beg) || RB_BIGNUM_TYPE_P(beg)) &&
(FIXNUM_P(end) || RB_BIGNUM_TYPE_P(end))) {
return int_range_sum(beg, end, excl, memo.v);
}
}
if (RB_TYPE_P(obj, T_HASH) &&
rb_method_basic_definition_p(CLASS_OF(obj), id_each))
hash_sum(obj, &memo);
else
rb_block_call(obj, id_each, 0, 0, enum_sum_i, (VALUE)&memo);
if (memo.float_value) {
return DBL2NUM(memo.f + memo.c);
}
else {
if (memo.n != 0)
memo.v = rb_fix_plus(LONG2FIX(memo.n), memo.v);
if (!UNDEF_P(memo.r)) {
memo.v = rb_rational_plus(memo.r, memo.v);
}
return memo.v;
}
}
|
#take(n) ⇒ Array
For non-negative integer n
, returns the first n
elements:
r = (1..4)
r.take(2) # => [1, 2]
r.take(0) # => []
h = {foo: 0, bar: 1, baz: 2, bat: 3}
h.take(2) # => [[:foo, 0], [:bar, 1]]
3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 |
# File 'enum.c', line 3567
static VALUE
enum_take(VALUE obj, VALUE n)
{
struct MEMO *memo;
VALUE result;
long len = NUM2LONG(n);
if (len < 0) {
rb_raise(rb_eArgError, "attempt to take negative size");
}
if (len == 0) return rb_ary_new2(0);
result = rb_ary_new2(len);
memo = MEMO_NEW(result, 0, len);
rb_block_call(obj, id_each, 0, 0, take_i, (VALUE)memo);
return result;
}
|
#take_while {|element| ... } ⇒ Array #take_while ⇒ Object
Calls the block with successive elements as long as the block returns a truthy value; returns an array of all elements up to that point:
(1..4).take_while{|i| i < 3 } # => [1, 2]
h = {foo: 0, bar: 1, baz: 2}
h.take_while{|element| key, value = *element; value < 2 }
# => [[:foo, 0], [:bar, 1]]
With no block given, returns an Enumerator.
3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 |
# File 'enum.c', line 3613
static VALUE
enum_take_while(VALUE obj)
{
VALUE ary;
RETURN_ENUMERATOR(obj, 0, 0);
ary = rb_ary_new();
rb_block_call(obj, id_each, 0, 0, take_while_i, ary);
return ary;
}
|
#tally(hash = {}) ⇒ Hash
When argument hash
is not given, returns a new hash whose keys are the distinct elements in self
; each integer value is the count of occurrences of each element:
%w[a b c b c a c b].tally # => {"a"=>2, "b"=>3, "c"=>3}
When argument hash
is given, returns hash
, possibly augmented; for each element ele
in self
:
-
Adds it as a key with a zero value if that key does not already exist:
hash[ele] = 0 unless hash.include?(ele)
-
Increments the value of key
ele
:hash[ele] += 1
This is useful for accumulating tallies across multiple enumerables:
h = {} # => {}
%w[a c d b c a].tally(h) # => {"a"=>2, "c"=>2, "d"=>1, "b"=>1}
%w[b a z].tally(h) # => {"a"=>3, "c"=>2, "d"=>1, "b"=>2, "z"=>1}
%w[b a m].tally(h) # => {"a"=>4, "c"=>2, "d"=>1, "b"=>3, "z"=>1, "m"=>1}
The key to be added or found for an element depends on the class of self
; see Enumerable in Ruby Classes.
Examples:
-
Array (and certain array-like classes): the key is the element (as above).
-
Hash (and certain hash-like classes): the key is the 2-element array formed from the key-value pair:
h = {} # => {} {foo: 'a', bar: 'b'}.tally(h) # => {[:foo, "a"]=>1, [:bar, "b"]=>1} {foo: 'c', bar: 'd'}.tally(h) # => {[:foo, "a"]=>1, [:bar, "b"]=>1, [:foo, "c"]=>1, [:bar, "d"]=>1} {foo: 'a', bar: 'b'}.tally(h) # => {[:foo, "a"]=>2, [:bar, "b"]=>2, [:foo, "c"]=>1, [:bar, "d"]=>1} {foo: 'c', bar: 'd'}.tally(h) # => {[:foo, "a"]=>2, [:bar, "b"]=>2, [:foo, "c"]=>2, [:bar, "d"]=>2}
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 |
# File 'enum.c', line 1282
static VALUE
enum_tally(int argc, VALUE *argv, VALUE obj)
{
VALUE hash;
if (rb_check_arity(argc, 0, 1)) {
hash = rb_to_hash_type(argv[0]);
rb_check_frozen(hash);
}
else {
hash = rb_hash_new();
}
return enum_hashify_into(obj, 0, 0, tally_i, hash);
}
|
#to_a(*args) ⇒ Array
Returns an array containing the items in self
:
(0..4).to_a # => [0, 1, 2, 3, 4]
729 730 731 732 733 734 735 736 737 |
# File 'enum.c', line 729
static VALUE
enum_to_a(int argc, VALUE *argv, VALUE obj)
{
VALUE ary = rb_ary_new();
rb_block_call_kw(obj, id_each, argc, argv, collect_all, ary, RB_PASS_CALLED_KEYWORDS);
return ary;
}
|
#to_h(*args) ⇒ Hash #to_h(*args) {|element| ... } ⇒ Hash
When self
consists of 2-element arrays, returns a hash each of whose entries is the key-value pair formed from one of those arrays:
[[:foo, 0], [:bar, 1], [:baz, 2]].to_h # => {:foo=>0, :bar=>1, :baz=>2}
When a block is given, the block is called with each element of self
; the block should return a 2-element array which becomes a key-value pair in the returned hash:
(0..3).to_h {|i| [i, i ** 2]} # => {0=>0, 1=>1, 2=>4, 3=>9}
Raises an exception if an element of self
is not a 2-element array, and a block is not passed.
786 787 788 789 790 791 |
# File 'enum.c', line 786
static VALUE
enum_to_h(int argc, VALUE *argv, VALUE obj)
{
rb_block_call_func *iter = rb_block_given_p() ? enum_to_h_ii : enum_to_h_i;
return enum_hashify(obj, argc, argv, iter);
}
|
#uniq ⇒ Array #uniq {|element| ... } ⇒ Array
With no block, returns a new array containing only unique elements; the array has no two elements e0
and e1
such that e0.eql?(e1)
:
%w[a b c c b a a b c].uniq # => ["a", "b", "c"]
[0, 1, 2, 2, 1, 0, 0, 1, 2].uniq # => [0, 1, 2]
With a block, returns a new array containing elements only for which the block returns a unique value:
a = [0, 1, 2, 3, 4, 5, 5, 4, 3, 2, 1]
a.uniq {|i| i.even? ? i : 0 } # => [0, 2, 4]
a = %w[a b c d e e d c b a a b c d e]
a.uniq {|c| c < 'c' } # => ["a", "c"]
4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 |
# File 'enum.c', line 4891
static VALUE
enum_uniq(VALUE obj)
{
VALUE hash, ret;
rb_block_call_func *const func =
rb_block_given_p() ? uniq_iter : uniq_func;
hash = rb_obj_hide(rb_hash_new());
rb_block_call(obj, id_each, 0, 0, func, hash);
ret = rb_hash_values(hash);
rb_hash_clear(hash);
return ret;
}
|
#zip(*other_enums) ⇒ Array #zip(*other_enums) {|array| ... } ⇒ nil
With no block given, returns a new array new_array
of size self.size whose elements are arrays. Each nested array new_array[n]
is of size other_enums.size+1
, and contains:
-
The
n
-th element of self. -
The
n
-th element of each of theother_enums
.
If all other_enums
and self are the same size, all elements are included in the result, and there is no nil
-filling:
a = [:a0, :a1, :a2, :a3]
b = [:b0, :b1, :b2, :b3]
c = [:c0, :c1, :c2, :c3]
d = a.zip(b, c)
d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
f = {foo: 0, bar: 1, baz: 2}
g = {goo: 3, gar: 4, gaz: 5}
h = {hoo: 6, har: 7, haz: 8}
d = f.zip(g, h)
d # => [
# [[:foo, 0], [:goo, 3], [:hoo, 6]],
# [[:bar, 1], [:gar, 4], [:har, 7]],
# [[:baz, 2], [:gaz, 5], [:haz, 8]]
# ]
If any enumerable in other_enums is smaller than self, fills to self.size
with nil
:
a = [:a0, :a1, :a2, :a3]
b = [:b0, :b1, :b2]
c = [:c0, :c1]
d = a.zip(b, c)
d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, nil], [:a3, nil, nil]]
If any enumerable in other_enums is larger than self, its trailing elements are ignored:
a = [:a0, :a1, :a2, :a3]
b = [:b0, :b1, :b2, :b3, :b4]
c = [:c0, :c1, :c2, :c3, :c4, :c5]
d = a.zip(b, c)
d # => [[:a0, :b0, :c0], [:a1, :b1, :c1], [:a2, :b2, :c2], [:a3, :b3, :c3]]
When a block is given, calls the block with each of the sub-arrays (formed as above); returns nil:
a = [:a0, :a1, :a2, :a3]
b = [:b0, :b1, :b2, :b3]
c = [:c0, :c1, :c2, :c3]
a.zip(b, c) {|sub_array| p sub_array} # => nil
Output:
[:a0, :b0, :c0]
[:a1, :b1, :c1]
[:a2, :b2, :c2]
[:a3, :b3, :c3]
3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 |
# File 'enum.c', line 3502
static VALUE
enum_zip(int argc, VALUE *argv, VALUE obj)
{
int i;
ID conv;
struct MEMO *memo;
VALUE result = Qnil;
VALUE args = rb_ary_new4(argc, argv);
int allary = TRUE;
argv = RARRAY_PTR(args);
for (i=0; i<argc; i++) {
VALUE ary = rb_check_array_type(argv[i]);
if (NIL_P(ary)) {
allary = FALSE;
break;
}
argv[i] = ary;
}
if (!allary) {
static const VALUE sym_each = STATIC_ID2SYM(id_each);
CONST_ID(conv, "to_enum");
for (i=0; 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]));
}
argv[i] = rb_funcallv(argv[i], conv, 1, &sym_each);
}
}
if (!rb_block_given_p()) {
result = rb_ary_new();
}
/* TODO: use NODE_DOT2 as memo(v, v, -) */
memo = MEMO_NEW(result, args, 0);
rb_block_call(obj, id_each, 0, 0, allary ? zip_ary : zip_i, (VALUE)memo);
return result;
}
|