module Enumerable - Documentation for Ruby 3.5 (original) (raw)

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:

Methods for Fetching

These methods return entries from the Enumerable, without modifying it:

Leading, trailing, or all elements:

Minimum and maximum value elements:

Groups, slices, and partitions:

Methods for Searching and Filtering

These methods return elements that meet a specified criterion:

Methods for Sorting

These methods return elements in sorted order:

Methods for Iterating

Other Methods

Usage

To use module Enumerable in a collection class:

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:

These Ruby standard library classes include Enumerable:

Virtually all methods in Enumerable call method each in the including class:

About the Examples

The example code snippets for the Enumerable methods:

Extended Methods

A Enumerable class may define extended methods. This section describes the standard behavior of extension methods for reference purposes.

size

Enumerator has a size method. It uses the size function argument passed to Enumerator.new.

e = Enumerator.new(-> { 3 }) {|y| p y; y.yield :a; y.yield :b; y.yield :c; :z } p e.size p e.next p e.next p e.next begin e.next rescue StopIteration p $!.result end

The result of the size function should represent the number of iterations (i.e., the number of times Enumerator::Yielder#yield is called). In the above example, the block calls yield three times, and the size function, +-> { 3 }+, returns 3 accordingly. The result of the size function can be an integer, Float::INFINITY, or nil. An integer means the exact number of times yield will be called, as shown above. Float::INFINITY indicates an infinite number of yield calls. nil means the number of yield calls is difficult or impossible to determine.

Many iteration methods return an Enumerator object with an appropriate size function if no block is given.

Examples:

["a", "b", "c"].each.size {a: "x", b: "y", c: "z"}.each.size (0..20).to_a.permutation.size loop.size (1..100).drop_while.size STDIN.each.size File.open("/etc/resolv.conf").each.size

The behavior of size for Range-based enumerators depends on the begin element:

Examples:

(10..42).each.size (10..42.9).each.size (10..).each.size ("a".."z").each.size ("a"..).each.size (1.0..9.0).each.size (..10).each.size

The Enumerable module itself does not define a size method. A class that includes Enumerable may define its own size method. It is recommended that such a size method be consistent with Enumerator#size.

Array and Hash implement size and return values consistent with Enumerator#size. IO and Dir do not define size, which is also consistent because the corresponding enumerator’s size function returns nil.

However, it is not strictly required for a class’s size method to match Enumerator#size. For example, File#size returns the number of bytes in the file, not the number of lines.

Public Instance Methods

Source

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; }

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?
%w[a b c d].all?
[1, 2, nil].all?
['a','b', false].all? [].all?

With argument pattern and no block, returns whether for each element element, pattern === element:

(1..4).all?(Integer)
(1..4).all?(Numeric)
(1..4).all?(Float)
%w[bar baz bat bam].all?(/ba/)
%w[bar baz bat bam].all?(/bar/)
%w[bar baz bat bam].all?('ba')
{foo: 0, bar: 1, baz: 2}.all?(Array) {foo: 0, bar: 1, baz: 2}.all?(Hash)
[].all?(Integer)

With a block given, returns whether the block returns a truthy value for every element:

(1..4).all? {|element| element < 5 }
(1..4).all? {|element| element < 4 }
{foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 3 } {foo: 0, bar: 1, baz: 2}.all? {|key, value| value < 2 }

Related: any?, none? one?.

Source

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; }

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?
%w[a b c d].any?
[1, false, nil].any? [].any?

With argument pattern and no block, returns whether for any element element, pattern === element:

[nil, false, 0].any?(Integer)
[nil, false, 0].any?(Numeric)
[nil, false, 0].any?(Float)
%w[bar baz bat bam].any?(/m/)
%w[bar baz bat bam].any?(/foo/)
%w[bar baz bat bam].any?('ba')
{foo: 0, bar: 1, baz: 2}.any?(Array) {foo: 0, bar: 1, baz: 2}.any?(Hash)
[].any?(Integer)

With a block given, returns whether the block returns a truthy value for any element:

(1..4).any? {|element| element < 2 }
(1..4).any? {|element| element < 1 }
{foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 1 } {foo: 0, bar: 1, baz: 2}.any? {|key, value| value < 0 }

Related: all?, none?, one?.

Source

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); }

Returns an enumerator object generated from this enumerator and given enumerables.

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

Source

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;

}

Each element in the returned enumerator is a 2-element array consisting of:

So that:

Example:

e = (0..10).chunk {|i| (i / 3).floor }

e.next e.next e.next e.next

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:

url = 'https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt' words = URI::open(url).readlines

e = words.chunk {|word| word.upcase[0] }

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

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

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

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 } }

Paragraphs separated by empty lines can be parsed as follows:

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

Source

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;

}

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 c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" } p c d = c.join(",") p d

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

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

Enumerable#slice_when does the same, except splitting when the block returns true instead of false.

Source

Also aliased as: map

Source

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;

}

Returns an array of all non-nil elements:

a = [nil, 0, nil, 'a', false, nil, false, nil, 'a', nil, 0, nil] a.compact

Source

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);

}

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
{foo: 0, bar: 1, baz: 2}.count

With argument object given, returns the number of elements that are == to object:

[0, 1, 2, 1].count(1)

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}
{foo: 0, bar: 1, baz: 2}.count {|key, value| value < 2}

Source

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;

}

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) } a a = [] ('a'..'d').cycle(2) {|element| a.push(element) } a a = [] {foo: 0, bar: 1, baz: 2}.cycle(2) {|element| a.push(element) } a

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.

Source

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;

}

For positive integer n, returns an array containing all but the first n elements:

r = (1..4) r.drop(3)
r.drop(2)
r.drop(1)
r.drop(0)
r.drop(50)

h = {foo: 0, bar: 1, baz: 2, bat: 3} h.drop(2)

Source

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;

}

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 } h = {foo: 0, bar: 1, baz: 2} a = h.drop_while{|element| key, value = *element; value < 2 } a

With no block given, returns an Enumerator.

e = (1..4).drop_while p e i = e.next; p i; e.feed(i < 3) i = e.next; p i; e.feed(i < 3) i = e.next; p i; e.feed(i < 3) begin e.next rescue StopIteration p $!.result end

Source

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;

}

Calls the block with each successive overlapped n-tuple of elements; returns self:

a = [] (1..5).each_cons(3) {|element| a.push(element) } a

a = [] h = {foo: 0, bar: 1, baz: 2, bam: 3} h.each_cons(2) {|element| a.push(element) } a

With no block given, returns an Enumerator.

Source

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; }

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) } a

a = [] h = {foo: 0, bar: 1, baz:2} h.each_entry {|element| a.push(element) }

a

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.

Source

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;

}

Calls the block with each successive disjoint n-tuple of elements; returns self:

a = [] (1..10).each_slice(3) {|tuple| a.push(tuple) } a

a = [] h = {foo: 0, bar: 1, baz: 2, bat: 3, bam: 4} h.each_slice(2) {|tuple| a.push(tuple) } a

With no block given, returns an Enumerator.

Source

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;

}

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 } h

h = {} %w[a b c d].each_with_index {|element, i| h[element] = i }

h

a = [] h = {foo: 0, bar: 1, baz: 2} h.each_with_index {|element, i| a.push([i, element]) }

a

With no block given, returns an Enumerator.

Source

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;

}

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) }

{foo: 0, bar: 1, baz: 2}.each_with_object({}) {|(k, v), h| h[v] = k }

With no block given, returns an Enumerator.

Source

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;

}

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? }
{foo: 0, bar: 1, baz: 2}.filter_map {|key, value| key if value.even? }

When no block given, returns an Enumerator.

Source

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;

}

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}

If no such element is found, calls if_none_proc and returns its return value.

(0..9).find(proc {false}) {|element| element > 12} {foo: 0, bar: 1, baz: 2}.find {|key, value| key.start_with?('b') }
{foo: 0, bar: 1, baz: 2}.find(proc {[]}) {|key, value| key.start_with?('c') }

With no block given, returns an Enumerator.

Source

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;

}

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')

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') } {foo: 0, bar: 1, baz: 2}.find_index {|key, value| value > 1 }

With no argument and no block given, returns an Enumerator.

Source

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; } }

Returns the first element or elements.

With no argument, returns the first element, or nil if there is none:

(1..4).first
%w[a b c].first
{foo: 1, bar: 1, baz: 2}.first [].first

With integer argument n, returns an array containing the first n elements that exist:

(1..4).first(2)
%w[a b c d].first(3)
%w[a b c d].first(50)
{foo: 1, bar: 1, baz: 2}.first(2) [].first(2)

Source

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;

}

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].flat_map {|element| [element, -element] }
[[0, 1], [2, 3]].flat_map {|e| e + [100] }
{foo: 0, bar: 1, baz: 2}.flat_map {|key, value| [key, value] }

With no block given, returns an Enumerator.

Alias: collect_concat.

Source

static VALUE enum_grep(VALUE obj, VALUE pat) { return enum_grep0(obj, pat, Qtrue); }

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/)
(1..10).grep(3..8)
['a', 'b', 0, 1].grep(Integer)

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 }

Related: grep_v.

Source

static VALUE enum_grep_v(VALUE obj, VALUE pat) { return enum_grep0(obj, pat, Qfalse); }

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/)
(1..10).grep_v(3..8)
['a', 'b', 0, 1].grep_v(Integer)

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 }

Related: grep.

Source

static VALUE enum_group_by(VALUE obj) { RETURN_SIZED_ENUMERATOR(obj, 0, 0, enum_size);

return enum_hashify(obj, 0, 0, group_by_i);

}

With a block given returns a hash:

Examples:

g = (1..6).group_by {|i| i%3 } g h = {foo: 0, bar: 1, baz: 0, bat: 1} g = h.group_by {|key, value| value } g

With no block given, returns an Enumerator.

Returns whether for any element object == element:

(1..4).include?(2)
(1..4).include?(5)
(1..4).include?('2')
%w[a b c d].include?('b')
%w[a b c d].include?('2')
{foo: 0, bar: 1, baz: 2}.include?(:foo)
{foo: 0, bar: 1, baz: 2}.include?('foo') {foo: 0, bar: 1, baz: 2}.include?(0)

Source

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;

}

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|

end

For example:

product = [ 2, 3, 4 ].inject(1) do |result, next_value| result * next_value end product

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

  1. Must be defined on the type of the result value
  2. Must accept a single parameter, the next value in the collection, and
  3. 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 s = [ "cat", " ", "dog" ].inject("The result is:", :+) s

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

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

String concatenation again:

s = [ "cat", " ", "dog" ].inject(:+) s

And an example that converts a hash to an array of two-element subarrays.

nested = {foo: 0, bar: 1}.inject([], :push) nested

Source

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; }

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| x2 + y2 == z**2 }.map {|y| [x, y, z] } } } end

p pythagorean_triples.take(10).force p pythagorean_triples.first(10)

p pythagorean_triples.take_while { |*, z| z < 100 }.force

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| ii }
{foo: 0, bar: 1, baz: 2}.map {|key, value| value
2}

With no block given, returns an Enumerator.

Source

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;

}

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..-1).max
%w[d c b a].max
{foo: 0, bar: 1, baz: 2}.max [].max

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..-1).max(2)
%w[d c b a].max(2)
{foo: 0, bar: 1, baz: 2}.max(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:

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 } h = {foo: 0, bar: 1, baz: 2} h.max {|pair1, pair2| pair1[1] <=> pair2[1] }
[].max {|a, b| a <=> b }

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 } h = {foo: 0, bar: 1, baz: 2} h.max(2) {|pair1, pair2| pair1[1] <=> pair2[1] }

[].max(2) {|a, b| a <=> b }

Related: min, minmax, max_by.

Source

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;

}

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 }
%w[a b c d].max_by {|element| -element.ord }
{foo: 0, bar: 1, baz: 2}.max_by {|key, value| -value } [].max_by {|element| -element }

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 }

%w[a b c d].max_by(2) {|element| -element.ord }

{foo: 0, bar: 1, baz: 2}.max_by(2) {|key, value| -value }

[].max_by(2) {|element| -element }

Returns an Enumerator if no block is given.

Related: max, minmax, min_by.

Source

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;

}

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
(-4..-1).min
%w[d c b a].min
{foo: 0, bar: 1, baz: 2}.min [].min

With positive integer argument n given, and no block, returns an array containing the first n minimum elements that exist:

(1..4).min(2)
(-4..-1).min(2)
%w[d c b a].min(2)
{foo: 0, bar: 1, baz: 2}.min(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:

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 } h = {foo: 0, bar: 1, baz: 2} h.min {|pair1, pair2| pair1[1] <=> pair2[1] } [].min {|a, b| a <=> b }

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 } h = {foo: 0, bar: 1, baz: 2} h.min(2) {|pair1, pair2| pair1[1] <=> pair2[1] }

[].min(2) {|a, b| a <=> b }

Related: min_by, minmax, max.

Source

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;

}

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 }
%w[a b c d].min_by {|element| -element.ord }
{foo: 0, bar: 1, baz: 2}.min_by {|key, value| -value } [].min_by {|element| -element }

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 }

%w[a b c d].min_by(2) {|element| -element.ord }

{foo: 0, bar: 1, baz: 2}.min_by(2) {|key, value| -value }

[].min_by(2) {|element| -element }

Returns an Enumerator if no block is given.

Related: min, minmax, max_by.

Source

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);

}

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
(-4..-1).minmax
%w[d c b a].minmax
{foo: 0, bar: 1, baz: 2}.minmax [].minmax

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 } h = {foo: 0, bar: 1, baz: 2} h.minmax {|pair1, pair2| pair1[1] <=> pair2[1] }

[].minmax {|a, b| a <=> b }

Related: min, max, minmax_by.

Source

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);

}

Returns a 2-element array containing the elements for which the block returns minimum and maximum values:

(1..4).minmax_by {|element| -element }

%w[a b c d].minmax_by {|element| -element.ord }

{foo: 0, bar: 1, baz: 2}.minmax_by {|key, value| -value }

[].minmax_by {|element| -element }

Returns an Enumerator if no block is given.

Related: max_by, minmax, min_by.

Source

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;

}

Returns whether no element meets a given criterion.

With no argument and no block, returns whether no element is truthy:

(1..4).none?
[nil, false].none?
{foo: 0}.none?
{foo: 0, bar: 1}.none? [].none?

With argument pattern and no block, returns whether for no element element, pattern === element:

[nil, false, 1.1].none?(Integer)
%w[bar baz bat bam].none?(/m/)
%w[bar baz bat bam].none?(/foo/)
%w[bar baz bat bam].none?('ba')
{foo: 0, bar: 1, baz: 2}.none?(Hash)
{foo: 0}.none?(Array)
[].none?(Integer)

With a block given, returns whether the block returns a truthy value for no element:

(1..4).none? {|element| element < 1 }
(1..4).none? {|element| element < 2 }
{foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 0 }
{foo: 0, bar: 1, baz: 2}.none? {|key, value| value < 1 }

Related: one?, all?, any?.

Source

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;

}

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?
[1, nil, false].one?
(1..4).one?
{foo: 0}.one?
{foo: 0, bar: 1}.one? [].one?

With argument pattern and no block, returns whether for exactly one element element, pattern === element:

[nil, false, 0].one?(Integer)
[nil, false, 0].one?(Numeric)
[nil, false, 0].one?(Float)
%w[bar baz bat bam].one?(/m/)
%w[bar baz bat bam].one?(/foo/)
%w[bar baz bat bam].one?('ba')
{foo: 0, bar: 1, baz: 2}.one?(Array) {foo: 0}.one?(Array)
[].one?(Integer)

With a block given, returns whether the block returns a truthy value for exactly one element:

(1..4).one? {|element| element < 2 }
(1..4).one? {|element| element < 1 }
{foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 1 }
{foo: 0, bar: 1, baz: 2}.one? {|key, value| value < 2 }

Related: none?, all?, any?.

Source

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);

}

With a block given, returns an array of two arrays:

Examples:

p = (1..4).partition {|i| i.even? } p p = ('a'..'d').partition {|c| c < 'c' } p h = {foo: 0, bar: 1, baz: 2, bat: 3} p = h.partition {|key, value| key.start_with?('b') } p p = h.partition {|key, value| value < 2 } p

With no block given, returns an Enumerator.

Related: Enumerable#group_by.

Source

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;

}

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? }
{foo: 0, bar: 1, baz: 2}.reject {|key, value| key if value.odd? }

When no block given, returns an Enumerator.

Related: select.

Source

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;

}

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) } a

a = [] %w[a b c d].reverse_each {|element| a.push(element) }

a

a = [] h.reverse_each {|element| a.push(element) }

a

With no block given, returns an Enumerator.

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 } a = {foo: 0, bar: 1, baz: 2}.select {|key, value| key.start_with?('b') } a

With no block given, returns an Enumerator.

Related: reject.

Source

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;

}

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

p e.map {|ll| ll[0...-1].map {|l| l.sub(/\\n\z/, "") }.join + ll.last }

Source

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;

}

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/) 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 } 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:

open("ChangeLog") { |f| f.slice_before(/\A\S/).each { |e| pp e } }

open("ChangeLog") { |f| f.slice_before { |line| /\A\S/ === line }.each { |e| pp e } }

“svn proplist -R” 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 } }

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(",")

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.

def wordwrap(words, maxwidth) Enumerator.new {|y|

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(" ") } puts "-"*10 enum.each { |ws| puts ws.join(" ") } puts "-"*10

mbox contains series of mails which start with Unix From line. So each mail can be extracted by slice before Unix From line.

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 } }

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 } }

Source

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;

}

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 c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" } p c d = c.join(",") p d

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

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

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

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

Enumerable#chunk_while does the same, except splitting when the block returns false instead of true.

Source

static VALUE enum_sort(VALUE obj) { return rb_ary_sort_bang(enum_to_a(0, 0, obj)); }

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
{foo: 0, bar: 1, baz: 2}.sort

With a block given, comparisons in the block determine the ordering. The block is called with two elements a and b, and must return:

Examples:

a = %w[b c a d] a.sort {|a, b| b <=> a } h = {foo: 0, bar: 1, baz: 2} h.sort {|a, b| b <=> a }

See also sort_by. It implements a Schwartzian transform which is useful when key computation or comparison is expensive.

Source

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;

}

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 }
a.sort_by {|s| -s.size }
h = {foo: 2, bar: 1, baz: 0} h.sort_by{|key, value| value } h.sort_by{|key, value| key }

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

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

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

This is exactly what sort_by does internally.

sorted = Dir["*"].sort_by { |f| test(?M, f) } sorted

To produce the reverse of a specific order, the following can be used:

ary.sort_by { ... }.reverse!

Source

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;
}

}

With no block given, returns the sum of initial_value and the elements:

(1..100).sum
(1..100).sum(1)
('a'..'d').sum('foo')

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

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| ii }
(1..4).sum(100) {|i| i
i }
h = {a: 0, b: 1, c: 2, d: 3, e: 4, f: 5} h.sum {|key, value| value.odd? ? value : 0 } ('a'..'f').sum('x') {|c| c < 'd' ? c : '' }

Source

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;

}

For non-negative integer n, returns the first n elements:

r = (1..4) r.take(2) r.take(0)

h = {foo: 0, bar: 1, baz: 2, bat: 3} h.take(2)

Source

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;

}

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 } h = {foo: 0, bar: 1, baz: 2} h.take_while{|element| key, value = *element; value < 2 }

With no block given, returns an Enumerator.

Source

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);

}

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

When argument hash is given, returns hash, possibly augmented; for each element ele in self:

This is useful for accumulating tallies across multiple enumerables:

h = {}
%w[a c d b c a].tally(h) %w[b a z].tally(h)
%w[b a m].tally(h)

The key to be added or found for an element depends on the class of self; see Enumerable in Ruby Classes.

Examples:

Source

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;

}

Returns an array containing the items in self:

(0..4).to_a

Source

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); }

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

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]}

Raises an exception if an element of self is not a 2-element array, and a block is not passed.

Source

def to_set(*args, &block) klass = if args.empty? Set else warn "passing arguments to Enumerable#to_set is deprecated", uplevel: 1 args.shift end klass.new(self, *args, &block) end

Makes a set from the enumerable object with given arguments. Passing arguments to this method is deprecated.

Source

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;

}

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
[0, 1, 2, 2, 1, 0, 0, 1, 2].uniq

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 } a = %w[a b c d e e d c b a a b c d e] a.uniq {|c| c < 'c' }

Source

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;

}

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:

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

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

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

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

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}

Output:

[:a0, :b0, :c0] [:a1, :b1, :c1] [:a2, :b2, :c2] [:a3, :b3, :c3]