module Enumerable - RDoc Documentation

# module Enumerable

## What’s Here¶ ↑

Module Enumerable provides methods that are useful to a collection class for:

- Querying

- Fetching

- Searching and Filtering

- Sorting

- Iterating

- And more.…

### Methods for Querying¶ ↑

These methods return information about the Enumerable other than the elements themselves:

- `member?` (aliased as `include?`): Returns `true` if `self == 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 given `object` or a given block.

- `slice_before`: Returns a new `Enumerator` whose entries are a partition of `self`, based either on a given `object` 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.

### Public Instance Methods

all? → true or false click to toggle source
all?(pattern) → true or false
all? {|element| ... } → true or false

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?`.

    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? → true or false click to toggle source
any?(pattern) → true or false
any? {|element| ... } → true or false

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?`.

    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) → enumerator click to toggle source

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]

    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| ... } → enumerator click to toggle source

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
    }

    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| bool } → an_enumerator click to toggle source

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`.

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

collect -> enumerator click to toggle source

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`.

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

Also aliased as: map
collect_concat()

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`.

Alias for: flat_map
compact → array click to toggle source

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]

    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 click to toggle source
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

    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 click to toggle source
cycle(n = nil) → enumerator

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`.

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

detect(*args)

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`.

Alias for: find
drop(n) → array click to toggle source

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

    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 click to toggle source
drop_while → enumerator

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`.

    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 click to toggle source
each_cons(n) → enumerator

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`.

    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 click to toggle source
each_entry(*args) → enumerator

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`.

    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 click to toggle source
each_slice(n) → enumerator

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`.

    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 click to toggle source
each_with_index(*args) → enumerator

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`.

    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 click to toggle source
each_with_object(object) → enumerator

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`.

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

entries(*args)

Returns an array containing the items in `self`:

    (0..4).to_a # => [0, 1, 2, 3, 4]

Alias for: to_a
filter()

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`.

Alias for: find_all
filter_map {|element| ... } → array click to toggle source
filter_map → enumerator

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`.

    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 or nil click to toggle source
find(if_none_proc = nil) → enumerator

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`.

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

Also aliased as: detect
find_all -> enumerator click to toggle source

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`.

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

Also aliased as: select, filter
find_index(object) → integer or nil click to toggle source
find_index {|element| ... } → integer or nil
find_index → enumerator

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`.

    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 → element or nil click to toggle source
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)                       # => []

    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 click to toggle source
flat_map → enumerator

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`.

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

Also aliased as: collect_concat
grep(pattern) → array click to toggle source
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`.

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

grep_v(pattern) → array click to toggle source
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`.

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

group_by {|element| ... } → hash click to toggle source
group_by → enumerator

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`.

    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) → true or false

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

Alias for: member?
inject(symbol) → object click to toggle source
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

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 #=> "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]]

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

Also aliased as: reduce
lazy → lazy_enumerator click to toggle source

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

    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 → enumerator

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`.

Alias for: collect
max → element click to toggle source
max(n) → array
max {|a, b| ... } → element
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`.

    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| ... } → element click to toggle source
max_by(n) {|element| ... } → array
max_by → enumerator
max_by(n) → enumerator

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`.

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

member?(object) -> true or false click to toggle source

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

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

Also aliased as: include?
min → element click to toggle source
min(n) → array
min {|a, b| ... } → element
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`.

    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| ... } → element click to toggle source
min_by(n) {|element| ... } → array
min_by → enumerator
min_by(n) → enumerator

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`.

    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 → [minimum, maximum] click to toggle source
minmax {|a, b| ... } → [minimum, maximum]

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`.

    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| ... } → [minimum, maximum] click to toggle source
minmax_by → enumerator

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`.

    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? → true or false click to toggle source
none?(pattern) → true or false
none? {|element| ... } → true or false

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?`.

    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? → true or false click to toggle source
one?(pattern) → true or false
one? {|element| ... } → true or false

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?`.

    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| ... } → [true_array, false_array] click to toggle source
partition → enumerator

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`.

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

reduce(p1 = v1, p2 = v2)

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

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 #=> "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]]

Alias for: inject
reject {|element| ... } → array click to toggle source
reject → enumerator

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`.

    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 click to toggle source
reverse_each(*args) → enumerator

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`.

    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 → 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 } # => [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`.

Alias for: find_all
slice_after(pattern) → an_enumerator click to toggle source
slice_after { |elt| bool } → an_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
    #=> [["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"]

    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) → enumerator click to toggle source
slice_before {|elt| ... } → 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/) # => #<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
      }
    }

    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| bool } → an_enumerator click to toggle source

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`.

    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 click to toggle source
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.

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

sort_by {|element| ... } → array click to toggle source
sort_by → enumerator

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!

    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) → number click to toggle source
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"

    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 click to toggle source

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

    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 click to toggle source
take_while → enumerator

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`.

    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 click to toggle source

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}

    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 click to toggle source

Returns an array containing the items in `self`:

    (0..4).to_a # => [0, 1, 2, 3, 4]

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

Also aliased as: entries
to_h(*args) → hash click to toggle source
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.

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

to_set(klass = Set, *args, &block) click to toggle source

Makes a set from the enumerable object with given arguments.

    # File ruby_3_4_1/prelude.rb, line 28
    def to_set(klass = Set, *args, &block)
      klass.new(self, *args, &block)
    end

uniq → array click to toggle source
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"]

    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 click to toggle source
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 the `other_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]

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