# module Enumerable(T)

##
Overview

The `Enumerable` mixin provides collection classes with several traversal, searching, filtering and querying methods.

Including types must provide an `#each` method, which yields successive members of the collection.

For example:

    class Three
      include Enumerable(Int32)

      def each(&)
        yield 1
        yield 2
        yield 3
      end
    end

    three = Three.new
    three.to_a                # => [1, 2, 3]
    three.select &.odd?       # => [1, 3]
    three.all? { |x| x < 10 } # => true

Note that most search and filter methods traverse an Enumerable eagerly, producing an `Array` as the result. For a lazy alternative refer to the `Iterator` and `Iterable` modules.

##
Direct including types

- Char::Reader
- Dir
- Hash(K, V)
- HTTP::Cookies
- HTTP::Headers
- Indexable(T)
- Iterator(T)
- LLVM::BasicBlockCollection
- LLVM::InstructionCollection
- Log::Metadata
- Range(B, E)
- Set(T)
- URI::Params
- XML::Attributes
- XML::NodeSet
- YAML::Nodes::Sequence

##
Defined in:

enumerable.cr
set.cr

##
Class Method Summary

- .element_type(x)

  Returns a value with the same type as an element of x, even if x is not an `Enumerable`.

##
Instance Method Summary

- #accumulate(initial : U) : Array(U) forall U

  Returns an array containing initial and its prefix sums with the elements in this collection.

- #accumulate : Array(T)

  Returns an array of the prefix sums of the elements in this collection.

- #accumulate(initial : U, &block : U, T -> U) : Array(U) forall U

  Returns an array containing initial and the successive values of applying a binary operation, specified by the given block, to this collection's elements.

- #accumulate(&block : T, T -> T) : Array(T)

  Returns an array containing the successive values of applying a binary operation, specified by the given block, to this collection's elements.

- #all?(& : T -> ) : Bool

  Returns `true` if the passed block is truthy for all elements of the collection.

- #all?(pattern) : Bool

  Returns `true` if `pattern === element` for all elements in this enumerable.

- #all? : Bool

  Returns `true` if all of the elements of the collection are truthy.

- #any?(& : T -> ) : Bool

  Returns `true` if the passed block is truthy for at least one element of the collection.

- #any?(pattern) : Bool

  Returns `true` if `pattern === element` for at least one element in this enumerable.

- #any? : Bool

  Returns `true` if at least one of the collection's members is truthy.

- #chunks(&block : T -> U) forall U

  Enumerates over the items, chunking them together based on the return value of the block.

- #compact_map(& : T -> _)

  Returns an `Array` with the results of running the block against each element of the collection, removing `nil` values.

- #count(& : T -> ) : Int32

  Returns the number of elements in the collection for which the passed block is truthy.

- #count(item) : Int32

  Returns the number of times that the passed item is present in the collection.

- #cycle(n, & : T -> ) : Nil

  Calls the given block for each element in this enumerable n times.

- #cycle(& : T -> ) : Nil

  Calls the given block for each element in this enumerable forever.

- #each(& : T -> )

  Must yield this collection's elements to the block.

- #each_cons(count : Int, reuse = false, &)

  Iterates over the collection yielding chunks of size count, but advancing one by one.

- #each_cons_pair(& : T, T -> ) : Nil

  Iterates over the collection yielding pairs of adjacent items, but advancing one by one.

- #each_slice(count : Int, reuse = false, &)

  Iterates over the collection in slices of size count, and runs the block for each of those.

- #each_step(n : Int, *, offset : Int = 0, & : T -> ) : Nil

  Iterates over the collection, yielding every nth element, starting with the first.

- #each_with_index(offset = 0, &)

  Iterates over the collection, yielding both the elements and their index.

- #each_with_object(obj : U, & : T, U -> ) : U forall U

  Iterates over the collection, passing each element and the initial object obj.

- #empty? : Bool

  Returns `true` if `self` does not contain any element.

- #find(if_none = nil, & : T -> )

  Returns the first element in the collection for which the passed block is truthy.

- #find!(& : T -> ) : T

  Returns the first element in the collection for which the passed block is truthy.

- #find_value(if_none = nil, & : T -> )

  Yields each value until the first truthy block result and returns that result.

- #first(&)

  Returns the first element in the collection, If the collection is empty, calls the block and returns its value.

- #first(count : Int) : Array(T)

  Returns an `Array` with the first count elements in the collection.

- #first : T

  Returns the first element in the collection.

- #first? : T | Nil

  Returns the first element in the collection.

- #flat_map(& : T -> _)

  Returns a new array with the concatenated results of running the block once for every element in the collection.

- #group_by(& : T -> U) forall U

  Returns a `Hash` whose keys are each different value that the passed block returned when run for each element in the collection, and which values are an `Array` of the elements for which the block returned that value.

- #in_groups_of(size : Int, filled_up_with : U = nil) forall U

  Returns an `Array` with chunks in the given size, eventually filled up with given value or `nil`.

- #in_groups_of(size : Int, filled_up_with : U = nil, reuse = false, &) forall U

  Yields a block with the chunks in the given size.

- #in_slices_of(size : Int) : Array(Array(T))

  Returns an `Array` with chunks in the given size.

- #includes?(obj) : Bool

  Returns `true` if the collection contains obj, `false` otherwise.

- #index(& : T -> ) : Int32 | Nil

  Returns the index of the first element for which the passed block is truthy.

- #index(obj) : Int32 | Nil

  Returns the first index of obj in the collection.

- #index!(& : T -> ) : Int32

  Returns the index of the first element for which the passed block is truthy.

- #index!(obj) : Int32

  Returns the first index of obj in the collection.

- #index_by(& : T -> U) : Hash(U, T) forall U

  Converts an `Enumerable` to a `Hash` by using the value returned by the block as the hash key.

- #join(io : IO, separator = "") : Nil

  Prints to io all the elements in the collection, separated by separator.

- #join(separator, io : IO) : Nil

  Prints to io all the elements in the collection, separated by separator.

  DEPRECATED Use `#join(io : IO, separator = "") instead`

- #join(separator = "") : String

  Returns a `String` created by concatenating the elements in the collection, separated by separator (defaults to none).

- #join(io : IO, separator = "", & : T, IO -> )

  Prints to io the concatenation of the elements, with the possibility of controlling how the printing is done via a block.

- #join(separator, io : IO, &)

  Prints to io the concatenation of the elements, with the possibility of controlling how the printing is done via a block.

  DEPRECATED Use `#join(io : IO, separator = "", & : T, IO ->) instead`

- #join(separator = "", & : T -> )

  Returns a `String` created by concatenating the results of passing the elements in the collection to the passed block, separated by separator (defaults to none).

- #map(& : T -> U) : Array(U) forall U

  Returns an `Array` with the results of running the block against each element of the collection.

- #map_with_index(offset = 0, & : T, Int32 -> U) : Array(U) forall U

  Like `#map`, but the block gets passed both the element and its index.

- #max(count : Int) : Array(T)

  Returns an array of the maximum count elements, sorted descending.

- #max : T

  Returns the element with the maximum value in the collection.

- #max? : T | Nil

  Like `#max` but returns `nil` if the collection is empty.

- #max_by(& : T -> U) : T forall U

  Returns the element for which the passed block returns with the maximum value.

- #max_by?(& : T -> U) : T | Nil forall U

  Like `#max_by` but returns `nil` if the collection is empty.

- #max_of(& : T -> U) : U forall U

  Like `#max_by` but instead of the element, returns the value returned by the block.

- #max_of?(& : T -> U) : U | Nil forall U

  Like `#max_of` but returns `nil` if the collection is empty.

- #min(count : Int) : Array(T)

  Returns an array of the minimum count elements, sorted ascending.

- #min : T

  Returns the element with the minimum value in the collection.

- #min? : T | Nil

  Like `#min` but returns `nil` if the collection is empty.

- #min_by(& : T -> U) : T forall U

  Returns the element for which the passed block returns with the minimum value.

- #min_by?(& : T -> U) : T | Nil forall U

  Like `#min_by` but returns `nil` if the collection is empty.

- #min_of(& : T -> U) : U forall U

  Like `#min_by` but instead of the element, returns the value returned by the block.

- #min_of?(& : T -> U) : U | Nil forall U

  Like `#min_of` but returns `nil` if the collection is empty.

- #minmax : Tuple(T, T)

  Returns a `Tuple` with both the minimum and maximum value.

- #minmax? : Tuple(T | Nil, T | Nil)

  Like `#minmax` but returns `{nil, nil}` if the collection is empty.

- #minmax_by(& : T -> U) : Tuple(T, T) forall U

  Returns a `Tuple` with both the minimum and maximum values according to the passed block.

- #minmax_by?(& : T -> U) : Tuple(T, T) | Tuple(Nil, Nil) forall U

  Like `#minmax_by` but returns `{nil, nil}` if the collection is empty.

- #minmax_of(& : T -> U) : Tuple(U, U) forall U

  Returns a `Tuple` with both the minimum and maximum value the block returns when passed the elements in the collection.

- #minmax_of?(& : T -> U) : Tuple(U, U) | Tuple(Nil, Nil) forall U

  Like `#minmax_of` but returns `{nil, nil}` if the collection is empty.

- #none?(& : T -> ) : Bool

  Returns `true` if the passed block is truthy for none of the elements of the collection.

- #none?(pattern) : Bool

  Returns `true` if `pattern === element` for no element in this enumerable.

- #none? : Bool

  Returns `true` if all of the elements of the collection are falsey.

- #one?(& : T -> ) : Bool

  Returns `true` if the passed block is truthy for exactly one of the elements of the collection.

- #one?(pattern) : Bool

  Returns `true` if `pattern === element` for just one element in this enumerable.

- #one? : Bool

  Returns `true` if only one element in this enumerable is truthy.

- #partition(& : T -> ) : Tuple(Array(T), Array(T))

  Returns a `Tuple` with two arrays.

- #partition(type : U.class) forall U

  Returns a `Tuple` with two arrays.

- #present? : Bool

  Returns `true` if `self` contains at least one element.

- #product(initial : Number)

  Multiplies initial and all the elements in the collection together.

- #product

  Multiplies all the elements in the collection together.

- #product(initial : Number, & : T -> )

  Multiplies initial and all results of the passed block for each element in the collection.

- #product(& : T -> _)

  Multiplies all results of the passed block for each element in the collection.

- #reduce(memo, &)

  Just like the other variant, but you can set the initial value of the accumulator.

- #reduce(&)

  Combines all elements in the collection by applying a binary operation, specified by a block, so as to reduce them to a single value.

- #reduce?(&)

  Similar to `#reduce`, but instead of raising when the input is empty, return `nil`

- #reject(& : T -> )

  Returns an `Array` with all the elements in the collection for which the passed block is falsey.

- #reject(type : U.class) forall U

  Returns an `Array` with all the elements in the collection that are not of the given type.

- #reject(pattern) : Array(T)

  Returns an `Array` with all the elements in the collection for which `pattern === element` is false.

- #sample(n : Int, random : Random = Random::DEFAULT) : Array(T)

  Returns an `Array` of n random elements from `self`, using the given random number generator.

- #sample(random : Random = Random::DEFAULT) : T

  Returns a random element from `self`, using the given random number generator.

- #select(& : T -> )

  Returns an `Array` with all the elements in the collection for which the passed block is truthy.

- #select(type : U.class) : Array(U) forall U

  Returns an `Array` with all the elements in the collection that are of the given type.

- #select(pattern) : Array(T)

  Returns an `Array` with all the elements in the collection for which `pattern === element`.

- #size : Int32

  Returns the number of elements in the collection.

- #skip(count : Int)

  Returns an `Array` with the first count elements removed from the original collection.

- #skip_while(& : T -> ) : Array(T)

  Skips elements up to, but not including, the first element for which the block is falsey, and returns an `Array` containing the remaining elements.

- #sum(initial)

  Adds initial and all the elements in the collection together.

- #sum

  Adds all the elements in the collection together.

- #sum(initial, & : T -> )

  Adds initial and all results of the passed block for each element in the collection.

- #sum(& : T -> )

  Adds all results of the passed block for each element in the collection.

- #take_while(& : T -> ) : Array(T)

  Passes elements to the block until the block returns a falsey value, then stops iterating and returns an `Array` of all prior elements.

- #tally(hash)

  Tallies the collection.

- #tally : Hash(T, Int32)

  Tallies the collection.

- #tally_by(hash, &)

  Tallies the collection.

- #tally_by(&block : T -> U) : Hash(U, Int32) forall U

  Tallies the collection.

- #to_a : Array(T)

  Returns an `Array` with all the elements in the collection.

- #to_a(& : T -> U) : Array(U) forall U

  Returns an `Array` with the results of running block against each element of the collection.

- #to_h

  Creates a `Hash` out of an Enumerable where each element is a 2 element structure (for instance a `Tuple` or an `Array`).

- #to_h(& : T -> Tuple(K, V)) forall K, V

  Creates a `Hash` out of `Tuple` pairs (key, value) returned from the block.

- #to_set : Set(T)

  Returns a new `Set` with each unique element in the enumerable.

- #to_set(&block : T -> U) : Set(U) forall U

  Returns a new `Set` with the unique results of running block against each element of the enumerable.

- #zip(*others : Indexable | Iterable | Iterator, &)

  Yields elements of `self` and others in tandem to the given block.

- #zip(*others : Indexable | Iterable | Iterator)

  Returns an `Array` of tuples populated with the elements of `self` and others traversed in tandem.

- #zip?(*others : Indexable | Iterable | Iterator, &)

  Yields elements of `self` and others in tandem to the given block.

- #zip?(*others : Indexable | Iterable | Iterator)

  Returns an `Array` of tuples populated with the elements of `self` and others traversed in tandem.

##
Class Method Detail

def self.element_type(x) #

Returns a value with the same type as an element of x, even if x is not an `Enumerable`.

Used by splat expansion inside array literals. For example, this code

    [1, *{2, 3.5}, 4]

will end up calling `typeof(1, ::Enumerable.element_type({2, 3.5}), 4)`.

NOTE there should never be a need to call this method outside the standard library.

##
Instance Method Detail

def accumulate(initial : U) : Array(U) forall U #

Returns an array containing initial and its prefix sums with the elements in this collection.

Expects `U` to respond to the `#+` method.

    [1, 2, 3, 4, 5].accumulate(6) # => [6, 7, 9, 12, 16, 21]

def accumulate : Array(T) #

Returns an array of the prefix sums of the elements in this collection. The first element of the returned array is same as the first element of `self`.

Expects all element types to respond to the `#+` method.

    [1, 2, 3, 4, 5, 6].accumulate # => [1, 3, 6, 10, 15, 21]

def accumulate(initial : U, &block : U, T -> U) : Array(U) forall U #

Returns an array containing initial and the successive values of applying a binary operation, specified by the given block, to this collection's elements.

Similar to `#accumulate(&block : T, T -> T)`, except the initial value is provided by an argument and needs not have the same type as the elements in the collection. This initial value is always present in the returned array.

    [1, 3, 5, 7].accumulate(9) { |x, y| x * y } # => [9, 9, 27, 135, 945]

def accumulate(&block : T, T -> T) : Array(T) #

Returns an array containing the successive values of applying a binary operation, specified by the given block, to this collection's elements.

For each element in the collection the block is passed an accumulator value and the element. The result becomes the new value for the accumulator and is also appended to the returned array. The initial value for the accumulator is the first element in the collection.

    [2, 3, 4, 5].accumulate { |x, y| x * y } # => [2, 6, 24, 120]

def all?(& : T -> ) : Bool #

Returns `true` if the passed block is truthy for all elements of the collection.

    ["ant", "bear", "cat"].all? { |word| word.size >= 3 } # => true
    ["ant", "bear", "cat"].all? { |word| word.size >= 4 } # => false

def all?(pattern) : Bool #

Returns `true` if `pattern === element` for all elements in this enumerable.

    [2, 3, 4].all?(1..5)        # => true
    [2, 3, 4].all?(Int32)       # => true
    [2, "a", 3].all?(String)    # => false
    %w[foo bar baz].all?(/o|a/) # => true

def all? : Bool #

Returns `true` if all of the elements of the collection are truthy.

    [nil, true, 99].all? # => false
    [15].all?            # => true

def any?(& : T -> ) : Bool #

Returns `true` if the passed block is truthy for at least one element of the collection.

    ["ant", "bear", "cat"].any? { |word| word.size >= 4 } # => true
    ["ant", "bear", "cat"].any? { |word| word.size > 4 }  # => false

def any?(pattern) : Bool #

Returns `true` if `pattern === element` for at least one element in this enumerable.

    [2, 3, 4].any?(1..3)      # => true
    [2, 3, 4].any?(5..10)     # => false
    [2, "a", 3].any?(String)  # => true
    %w[foo bar baz].any?(/a/) # => true

def any? : Bool #

Returns `true` if at least one of the collection's members is truthy.

    [nil, true, 99].any? # => true
    [nil, false].any?    # => false
    ([] of Int32).any?   # => false

- `#present?` does not consider truthiness of elements.
- `#any?(&)` and `#any(pattern)` allow custom conditions.

NOTE `#any?` usually has the same semantics as `#present?`. They only differ if the element type can be falsey (i.e. `T <= Nil || T <= Pointer || T <= Bool`). It's typically advised to prefer `#present?` unless these specific truthiness semantics are required.

def chunks(&block : T -> U) forall U #

Enumerates over the items, chunking them together based on the return value of the block.

Consecutive elements which return the same block value are chunked together.

For example, consecutive even numbers and odd numbers can be chunked as follows.

    ary = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5].chunks { |n| n.even? }
    ary # => [{false, [3, 1]}, {true, [4]}, {false, [1, 5, 9]}, {true, [2, 6]}, {false, [5, 3, 5]}]

The following key values have special meaning:

- `Enumerable::Chunk::Drop` specifies that the elements should be dropped
- `Enumerable::Chunk::Alone` specifies that the element should be chunked by itself

See also: `Iterator#chunk`.

def compact_map(& : T -> _) #

Returns an `Array` with the results of running the block against each element of the collection, removing `nil` values.

    ["Alice", "Bob"].map { |name| name.match(/^A./) }         # => [Regex::MatchData("Al"), nil]
    ["Alice", "Bob"].compact_map { |name| name.match(/^A./) } # => [Regex::MatchData("Al")]

def count(& : T -> ) : Int32 #

Returns the number of elements in the collection for which the passed block is truthy.

    [1, 2, 3, 4].count { |i| i % 2 == 0 } # => 2

def count(item) : Int32 #

Returns the number of times that the passed item is present in the collection.

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

def cycle(n, & : T -> ) : Nil #

Calls the given block for each element in this enumerable n times.

def cycle(& : T -> ) : Nil #

Calls the given block for each element in this enumerable forever.

abstract def each(& : T -> ) #

Must yield this collection's elements to the block.

def each_cons(count : Int, reuse = false, &) #

Iterates over the collection yielding chunks of size count, but advancing one by one.

    [1, 2, 3, 4, 5].each_cons(2) do |cons|
      puts cons
    end

Prints:

    [1, 2]
    [2, 3]
    [3, 4]
    [4, 5]

By default, a new array is created and yielded for each consecutive slice of elements.

- If reuse is given, the array can be reused
- If reuse is `true`, the method will create a new array and reuse it.
- If reuse is an instance of `Array`, `Deque` or a similar collection type (implementing `#<<`, `#shift` and `#size`) it will be used.
- If reuse is falsey, the array will not be reused.

This can be used to prevent many memory allocations when each slice of interest is to be used in a read-only fashion.

Chunks of two items can be iterated using `#each_cons_pair`, an optimized implementation for the special case of `count == 2` which avoids heap allocations.

def each_cons_pair(& : T, T -> ) : Nil #

Iterates over the collection yielding pairs of adjacent items, but advancing one by one.

    [1, 2, 3, 4, 5].each_cons_pair do |a, b|
      puts "#{a}, #{b}"
    end

Prints:

    1, 2
    2, 3
    3, 4
    4, 5

Chunks of more than two items can be iterated using `#each_cons`. This method is just an optimized implementation for the special case of `count == 2` to avoid heap allocations.

def each_slice(count : Int, reuse = false, &) #

Iterates over the collection in slices of size count, and runs the block for each of those.

    [1, 2, 3, 4, 5].each_slice(2) do |slice|
      puts slice
    end

Prints:

    [1, 2]
    [3, 4]
    [5]

Note that the last one can be smaller.

By default, a new array is created and yielded for each slice.

- If reuse is given, the array can be reused
- If reuse is an `Array`, this array will be reused
- If reuse is truthy, the method will create a new array and reuse it.

This can be used to prevent many memory allocations when each slice of interest is to be used in a read-only fashion.

def each_step(n : Int, *, offset : Int = 0, & : T -> ) : Nil #

Iterates over the collection, yielding every nth element, starting with the first.

    %w[Alice Bob Charlie David].each_step(2) do |user|
      puts "User: #{user}"
    end

Prints:

    User: Alice
    User: Charlie

Accepts an optional offset parameter

    %w[Alice Bob Charlie David].each_step(2, offset: 1) do |user|
      puts "User: #{user}"
    end

Which would print:

    User: Bob
    User: David

def each_with_index(offset = 0, &) #

Iterates over the collection, yielding both the elements and their index.

    ["Alice", "Bob"].each_with_index do |user, i|
      puts "User ##{i}: #{user}"
    end

Prints:

    User # 0: Alice
    User # 1: Bob

Accepts an optional offset parameter, which tells it to start counting from there. So, a more human friendly version of the previous snippet would be:

    ["Alice", "Bob"].each_with_index(1) do |user, i|
      puts "User ##{i}: #{user}"
    end

Which would print:

    User # 1: Alice
    User # 2: Bob

def each_with_object(obj : U, & : T, U -> ) : U forall U #

Iterates over the collection, passing each element and the initial object obj. Returns that object.

    hash = ["Alice", "Bob"].each_with_object({} of String => Int32) do |user, sizes|
      sizes[user] = user.size
    end
    hash # => {"Alice" => 5, "Bob" => 3}

def empty? : Bool #

Returns `true` if `self` does not contain any element.

    ([] of Int32).empty? # => true
    ([1]).empty?         # => false
    [nil, false].empty?  # => false

- `#present?` returns the inverse.

def find(if_none = nil, & : T -> ) #

Returns the first element in the collection for which the passed block is truthy.

Accepts an optional parameter if_none, to set what gets returned if no element is found (defaults to `nil`).

    [1, 2, 3, 4].find { |i| i > 2 }     # => 3
    [1, 2, 3, 4].find { |i| i > 8 }     # => nil
    [1, 2, 3, 4].find(-1) { |i| i > 8 } # => -1

def find!(& : T -> ) : T #

Returns the first element in the collection for which the passed block is truthy. Raises `Enumerable::NotFoundError` if there is no element for which the block is truthy.

    [1, 2, 3, 4].find! { |i| i > 2 } # => 3
    [1, 2, 3, 4].find! { |i| i > 8 } # => raises Enumerable::NotFoundError

def find_value(if_none = nil, & : T -> ) #

Yields each value until the first truthy block result and returns that result.

Accepts an optional parameter `if_none`, to set what gets returned if no element is found (defaults to `nil`).

    [1, 2, 3, 4].find_value { |i| i > 2 }     # => true
    [1, 2, 3, 4].find_value { |i| i > 8 }     # => nil
    [1, 2, 3, 4].find_value(-1) { |i| i > 8 } # => -1

def first(&) #

Returns the first element in the collection, If the collection is empty, calls the block and returns its value.

    ([1, 2, 3]).first { 4 }   # => 1
    ([] of Int32).first { 4 } # => 4

def first(count : Int) : Array(T) #

Returns an `Array` with the first count elements in the collection.

If count is bigger than the number of elements in the collection, returns as many as possible. This include the case of calling it over an empty collection, in which case it returns an empty array.

def first : T #

Returns the first element in the collection. Raises `Enumerable::EmptyError` if the collection is empty.

    ([1, 2, 3]).first   # => 1
    ([] of Int32).first # raises Enumerable::EmptyError

def first? : T | Nil #

Returns the first element in the collection. When the collection is empty, returns `nil`.

    ([1, 2, 3]).first?   # => 1
    ([] of Int32).first? # => nil

def flat_map(& : T -> _) #

Returns a new array with the concatenated results of running the block once for every element in the collection. Only `Array` and `Iterator` results are concatenated; every other value is directly appended to the new array.

    array = ["Alice", "Bob"].flat_map do |user|
      user.chars
    end
    array # => ['A', 'l', 'i', 'c', 'e', 'B', 'o', 'b']

def group_by(& : T -> U) forall U #

Returns a `Hash` whose keys are each different value that the passed block returned when run for each element in the collection, and which values are an `Array` of the elements for which the block returned that value.

    ["Alice", "Bob", "Ary"].group_by { |name| name.size } # => {5 => ["Alice"], 3 => ["Bob", "Ary"]}

def in_groups_of(size : Int, filled_up_with : U = nil) forall U #

Returns an `Array` with chunks in the given size, eventually filled up with given value or `nil`.

    [1, 2, 3].in_groups_of(2, 0) # => [[1, 2], [3, 0]]
    [1, 2, 3].in_groups_of(2)    # => [[1, 2], [3, nil]]

def in_groups_of(size : Int, filled_up_with : U = nil, reuse = false, &) forall U #

Yields a block with the chunks in the given size.

    [1, 2, 4].in_groups_of(2, 0) { |e| p e.sum }
    # => 3
    # => 4

By default, a new array is created and yielded for each group.

- If reuse is given, the array can be reused
- If reuse is an `Array`, this array will be reused
- If reuse is truthy, the method will create a new array and reuse it.

This can be used to prevent many memory allocations when each slice of interest is to be used in a read-only fashion.

def in_slices_of(size : Int) : Array(Array(T)) #

Returns an `Array` with chunks in the given size. Last chunk can be smaller depending on the number of remaining items.

    [1, 2, 3].in_slices_of(2) # => [[1, 2], [3]]

def includes?(obj) : Bool #

Returns `true` if the collection contains obj, `false` otherwise.

    [1, 2, 3].includes?(2) # => true
    [1, 2, 3].includes?(5) # => false

def index(& : T -> ) : Int32 | Nil #

Returns the index of the first element for which the passed block is truthy.

    ["Alice", "Bob"].index { |name| name.size < 4 } # => 1 (Bob's index)

Returns `nil` if the block is not truthy for any element.

def index(obj) : Int32 | Nil #

Returns the first index of obj in the collection.

    ["Alice", "Bob"].index("Alice") # => 0

Returns `nil` if obj is not in the collection.

def index!(& : T -> ) : Int32 #

Returns the index of the first element for which the passed block is truthy.

    ["Alice", "Bob"].index! { |name| name.size < 4 } # => 1 (Bob's index)

Raises `Enumerable::NotFoundError` if there is no element for which the block is truthy.

def index!(obj) : Int32 #

Returns the first index of obj in the collection.

    ["Alice", "Bob"].index!("Alice") # => 0

Raises `Enumerable::NotFoundError` if obj is not in the collection.

def index_by(& : T -> U) : Hash(U, T) forall U #

Converts an `Enumerable` to a `Hash` by using the value returned by the block as the hash key. Be aware, if two elements return the same value as a key one will override the other. If you want to keep all values, then you should probably use `#group_by` instead.

    ["Anna", "Ary", "Alice"].index_by { |e| e.size }
    # => {4 => "Anna", 3 => "Ary", 5 => "Alice"}
    ["Anna", "Ary", "Alice", "Bob"].index_by { |e| e.size }
    # => {4 => "Anna", 3 => "Bob", 5 => "Alice"}

def join(io : IO, separator = "") : Nil #

Prints to io all the elements in the collection, separated by separator.

    [1, 2, 3, 4, 5].join(STDOUT, ", ")

Prints:

    1, 2, 3, 4, 5

def join(separator, io : IO) : Nil #

Prints to io all the elements in the collection, separated by separator.

    [1, 2, 3, 4, 5].join(STDOUT, ", ")

Prints:

    1, 2, 3, 4, 5

DEPRECATED Use `#join(io : IO, separator = "") instead`

def join(separator = "") : String #

Returns a `String` created by concatenating the elements in the collection, separated by separator (defaults to none).

    [1, 2, 3, 4, 5].join(", ") # => "1, 2, 3, 4, 5"

def join(io : IO, separator = "", & : T, IO -> ) #

Prints to io the concatenation of the elements, with the possibility of controlling how the printing is done via a block.

    [1, 2, 3, 4, 5].join(STDOUT, ", ") { |i, io| io << "(#{i})" }

Prints:

    (1), (2), (3), (4), (5)

def join(separator, io : IO, &) #

Prints to io the concatenation of the elements, with the possibility of controlling how the printing is done via a block.

    [1, 2, 3, 4, 5].join(STDOUT, ", ") { |i, io| io << "(#{i})" }

Prints:

    (1), (2), (3), (4), (5)

DEPRECATED Use `#join(io : IO, separator = "", & : T, IO ->) instead`

def join(separator = "", & : T -> ) #

Returns a `String` created by concatenating the results of passing the elements in the collection to the passed block, separated by separator (defaults to none).

    [1, 2, 3, 4, 5].join(", ") { |i| -i } # => "-1, -2, -3, -4, -5"

def map(& : T -> U) : Array(U) forall U #

Returns an `Array` with the results of running the block against each element of the collection.

    [1, 2, 3].map { |i| i * 10 } # => [10, 20, 30]

def map_with_index(offset = 0, & : T, Int32 -> U) : Array(U) forall U #

Like `#map`, but the block gets passed both the element and its index.

    ["Alice", "Bob"].map_with_index { |name, i| "User ##{i}: #{name}" }
    # => ["User #0: Alice", "User #1: Bob"]

Accepts an optional offset parameter, which tells it to start counting from there.

def max(count : Int) : Array(T) #

Returns an array of the maximum count elements, sorted descending.

It compares using `<=>` so it will work for any type that supports that method.

    [7, 5, 2, 4, 9].max(3)                 # => [9, 7, 5]
    %w[Eve Alice Bob Mallory Carol].max(2) # => ["Mallory", "Eve"]

Returns all elements sorted descending if count is greater than the number of elements in the source.

Raises `Enumerable::ArgumentError` if count is negative or if any elements are not comparable.

def max : T #

Returns the element with the maximum value in the collection.

It compares using `>` so it will work for any type that supports that method.

    [1, 2, 3].max        # => 3
    ["Alice", "Bob"].max # => "Bob"

Raises `Enumerable::EmptyError` if the collection is empty.

def max? : T | Nil #

Like `#max` but returns `nil` if the collection is empty.

def max_by(& : T -> U) : T forall U #

Returns the element for which the passed block returns with the maximum value.

It compares using `>` so the block must return a type that supports that method

    ["Alice", "Bob"].max_by { |name| name.size } # => "Alice"

Raises `Enumerable::EmptyError` if the collection is empty.

def max_by?(& : T -> U) : T | Nil forall U #

Like `#max_by` but returns `nil` if the collection is empty.

def max_of(& : T -> U) : U forall U #

Like `#max_by` but instead of the element, returns the value returned by the block.

    ["Alice", "Bob"].max_of { |name| name.size } # => 5 (Alice's size)

def max_of?(& : T -> U) : U | Nil forall U #

Like `#max_of` but returns `nil` if the collection is empty.

def min(count : Int) : Array(T) #

Returns an array of the minimum count elements, sorted ascending.

It compares using `<=>` so it will work for any type that supports that method.

    [7, 5, 2, 4, 9].min(3)                 # => [2, 4, 5]
    %w[Eve Alice Bob Mallory Carol].min(2) # => ["Alice", "Bob"]

Returns all elements sorted ascending if count is greater than the number of elements in the source.

Raises `Enumerable::ArgumentError` if count is negative or if any elements are not comparable.

def min : T #

Returns the element with the minimum value in the collection.

It compares using `<` so it will work for any type that supports that method.

    [1, 2, 3].min        # => 1
    ["Alice", "Bob"].min # => "Alice"

Raises `Enumerable::EmptyError` if the collection is empty.

def min? : T | Nil #

Like `#min` but returns `nil` if the collection is empty.

def min_by(& : T -> U) : T forall U #

Returns the element for which the passed block returns with the minimum value.

It compares using `<` so the block must return a type that supports that method

    ["Alice", "Bob"].min_by { |name| name.size } # => "Bob"

Raises `Enumerable::EmptyError` if the collection is empty.

def min_by?(& : T -> U) : T | Nil forall U #

Like `#min_by` but returns `nil` if the collection is empty.

def min_of(& : T -> U) : U forall U #

Like `#min_by` but instead of the element, returns the value returned by the block.

    ["Alice", "Bob"].min_of { |name| name.size } # => 3 (Bob's size)

def min_of?(& : T -> U) : U | Nil forall U #

Like `#min_of` but returns `nil` if the collection is empty.

def minmax : Tuple(T, T) #

Returns a `Tuple` with both the minimum and maximum value.

    [1, 2, 3].minmax # => {1, 3}

Raises `Enumerable::EmptyError` if the collection is empty.

def minmax? : Tuple(T | Nil, T | Nil) #

Like `#minmax` but returns `{nil, nil}` if the collection is empty.

def minmax_by(& : T -> U) : Tuple(T, T) forall U #

Returns a `Tuple` with both the minimum and maximum values according to the passed block.

    ["Alice", "Bob", "Carl"].minmax_by { |name| name.size } # => {"Bob", "Alice"}

Raises `Enumerable::EmptyError` if the collection is empty.

def minmax_by?(& : T -> U) : Tuple(T, T) | Tuple(Nil, Nil) forall U #

Like `#minmax_by` but returns `{nil, nil}` if the collection is empty.

def minmax_of(& : T -> U) : Tuple(U, U) forall U #

Returns a `Tuple` with both the minimum and maximum value the block returns when passed the elements in the collection.

    ["Alice", "Bob", "Carl"].minmax_of { |name| name.size } # => {3, 5}

Raises `Enumerable::EmptyError` if the collection is empty.

def minmax_of?(& : T -> U) : Tuple(U, U) | Tuple(Nil, Nil) forall U #

Like `#minmax_of` but returns `{nil, nil}` if the collection is empty.

def none?(& : T -> ) : Bool #

Returns `true` if the passed block is truthy for none of the elements of the collection.

    [1, 2, 3].none? { |i| i > 5 } # => true

It's the opposite of `#all?`.

def none?(pattern) : Bool #

Returns `true` if `pattern === element` for no element in this enumerable.

    [2, 3, 4].none?(5..7)      # => true
    [2, "a", 3].none?(String)  # => false
    %w[foo bar baz].none?(/e/) # => true

def none? : Bool #

Returns `true` if all of the elements of the collection are falsey.

    [nil, false].none?       # => true
    [nil, false, true].none? # => false

It's the opposite of `#all?`.

def one?(& : T -> ) : Bool #

Returns `true` if the passed block is truthy for exactly one of the elements of the collection.

    [1, 2, 3].one? { |i| i > 2 } # => true
    [1, 2, 3].one? { |i| i > 1 } # => false

def one?(pattern) : Bool #

Returns `true` if `pattern === element` for just one element in this enumerable.

    [1, 10, 100].one?(7..14)   # => true
    [2, "a", 3].one?(Int32)    # => false
    %w[foo bar baz].one?(/oo/) # => true

def one? : Bool #

Returns `true` if only one element in this enumerable is truthy.

    [1, false, false].one? # => true
    [1, false, 3].one?     # => false
    [1].one?               # => true
    [false].one?           # => false

def partition(& : T -> ) : Tuple(Array(T), Array(T)) #

Returns a `Tuple` with two arrays. The first one contains the elements in the collection for which the passed block is truthy, and the second one those for which the block is falsey.

    [1, 2, 3, 4, 5, 6].partition { |i| i % 2 == 0 } # => {[2, 4, 6], [1, 3, 5]}

def partition(type : U.class) forall U #

Returns a `Tuple` with two arrays. The first one contains the elements in the collection that are of the given type, and the second one that are not of the given type.

    ints, others = [1, true, nil, 3, false, "string", 'c'].partition(Int32)
    ints           # => [1, 3]
    others         # => [true, nil, false, "string", 'c']
    typeof(ints)   # => Array(Int32)
    typeof(others) # => Array(String | Char | Nil)

def present? : Bool #

Returns `true` if `self` contains at least one element.

    ([] of Int32).present? # => false
    ([1]).present?         # => true
    [nil, false].present?  # => true

- `#empty?` returns the inverse.
- `#any?` considers only truthy elements.
- `#any?(&)` and `#any(pattern)` allow custom conditions.

def product(initial : Number) #

Multiplies initial and all the elements in the collection together. The type of initial will be the type of the product, so use this if (for instance) you need to specify a large enough type to avoid overflow.

Expects all element types to respond to `#*` method.

    [1, 2, 3, 4, 5, 6].product(7) # => 5040

If the collection is empty, returns initial.

    ([] of Int32).product(7) # => 7

def product #

Multiplies all the elements in the collection together.

Expects all element types to respond to `#*` method.

    [1, 2, 3, 4, 5, 6].product # => 720

This method calls `.multiplicative_identity` on the element type to determine the type of the product value.

If the collection is empty, returns `multiplicative_identity`.

    ([] of Int32).product # => 1

def product(initial : Number, & : T -> ) #

Multiplies initial and all results of the passed block for each element in the collection.

    ["Alice", "Bob"].product(2) { |name| name.size } # => 30 (2 * 5 * 3)

Expects all types returned from the block to respond to `#*` method.

If the collection is empty, returns `1`.

    ([] of String).product(1) { |name| name.size } # => 1

def product(& : T -> _) #

Multiplies all results of the passed block for each element in the collection.

    ["Alice", "Bob"].product { |name| name.size } # => 15 (5 * 3)

Expects all types returned from the block to respond to `#*` method.

This method calls `.multiplicative_identity` on the element type to determine the type of the product value. Hence, it can fail to compile if `.multiplicative_identity` fails to determine a safe type, e.g., in case of union types. In such cases, use `#product(initial)` with an initial value of the expected type of the product value.

If the collection is empty, returns `multiplicative_identity`.

    ([] of Int32).product { |x| x + 1 } # => 1

def reduce(memo, &) #

Just like the other variant, but you can set the initial value of the accumulator.

    [1, 2, 3, 4, 5].reduce(10) { |acc, i| acc + i }             # => 25
    [1, 2, 3].reduce([] of Int32) { |memo, i| memo.unshift(i) } # => [3, 2, 1]

def reduce(&) #

Combines all elements in the collection by applying a binary operation, specified by a block, so as to reduce them to a single value.

For each element in the collection the block is passed an accumulator value (memo) and the element. The result becomes the new value for memo. At the end of the iteration, the final value of memo is the return value for the method. The initial value for the accumulator is the first element in the collection. If the collection has only one element, that element is returned.

Raises `Enumerable::EmptyError` if the collection is empty.

    [1, 2, 3, 4, 5].reduce { |acc, i| acc + i } # => 15
    [1].reduce { |acc, i| acc + i }             # => 1
    ([] of Int32).reduce { |acc, i| acc + i }   # raises Enumerable::EmptyError

The block is not required to return a `T`, in which case the accumulator's type includes whatever the block returns.

    # `acc` is an `Int32 | String`
    [1, 2, 3, 4, 5].reduce { |acc, i| "#{acc}-#{i}" } # => "1-2-3-4-5"
    [1].reduce { |acc, i| "#{acc}-#{i}" }             # => 1

def reduce?(&) #

Similar to `#reduce`, but instead of raising when the input is empty, return `nil`

    ([] of Int32).reduce? { |acc, i| acc + i } # => nil

def reject(& : T -> ) #

Returns an `Array` with all the elements in the collection for which the passed block is falsey.

    [1, 2, 3, 4, 5, 6].reject { |i| i % 2 == 0 } # => [1, 3, 5]

def reject(type : U.class) forall U #

Returns an `Array` with all the elements in the collection that are not of the given type.

    ints = [1, true, 3, false].reject(Bool)
    ints         # => [1, 3]
    typeof(ints) # => Array(Int32)

def reject(pattern) : Array(T) #

Returns an `Array` with all the elements in the collection for which `pattern === element` is false.

    [1, 3, 2, 5, 4, 6].reject(3..5) # => [1, 2, 6]

def sample(n : Int, random : Random = Random::DEFAULT) : Array(T) #

Returns an `Array` of n random elements from `self`, using the given random number generator. All elements have equal probability of being drawn. Sampling is done without replacement; if n is larger than the size of this collection, the returned `Array` has the same size as `self`.

Raises `ArgumentError` if n is negative.

    [1, 2, 3, 4, 5].sample(2)                # => [3, 5]
    {1, 2, 3, 4, 5}.sample(2)                # => [3, 4]
    {1, 2, 3, 4, 5}.sample(2, Random.new(1)) # => [1, 5]

def sample(random : Random = Random::DEFAULT) : T #

Returns a random element from `self`, using the given random number generator. All elements have equal probability of being drawn.

Raises `IndexError` if `self` is empty.

    a = [1, 2, 3]
    a.sample                # => 2
    a.sample                # => 1
    a.sample(Random.new(1)) # => 3

def select(& : T -> ) #

Returns an `Array` with all the elements in the collection for which the passed block is truthy.

    [1, 2, 3, 4, 5, 6].select { |i| i % 2 == 0 } # => [2, 4, 6]

def select(type : U.class) : Array(U) forall U #

Returns an `Array` with all the elements in the collection that are of the given type.

    ints = [1, true, nil, 3, false].select(Int32)
    ints         # => [1, 3]
    typeof(ints) # => Array(Int32)

def select(pattern) : Array(T) #

Returns an `Array` with all the elements in the collection for which `pattern === element`.

    [1, 3, 2, 5, 4, 6].select(3..5) # => [3, 5, 4]
    ["Alice", "Bob"].select(/^A/)   # => ["Alice"]

def size : Int32 #

Returns the number of elements in the collection.

    [1, 2, 3, 4].size # => 4

def skip(count : Int) #

Returns an `Array` with the first count elements removed from the original collection.

If count is bigger than the number of elements in the collection, returns an empty array.

    [1, 2, 3, 4, 5, 6].skip(3) # => [4, 5, 6]

def skip_while(& : T -> ) : Array(T) #

Skips elements up to, but not including, the first element for which the block is falsey, and returns an `Array` containing the remaining elements.

    [1, 2, 3, 4, 5, 0].skip_while { |i| i < 3 } # => [3, 4, 5, 0]

def sum(initial) #

Adds initial and all the elements in the collection together. The type of initial will be the type of the sum, so use this if (for instance) you need to specify a large enough type to avoid overflow.

Expects all element types to respond to `#+` method.

    [1, 2, 3, 4, 5, 6].sum(7) # => 28

If the collection is empty, returns initial.

    ([] of Int32).sum(7) # => 7

def sum #

Adds all the elements in the collection together.

Expects all element types to respond to `#+` method.

    [1, 2, 3, 4, 5, 6].sum # => 21

This method calls `.additive_identity` on the yielded type to determine the type of the sum value.

If the collection is empty, returns `additive_identity`.

    ([] of Int32).sum # => 0

def sum(initial, & : T -> ) #

Adds initial and all results of the passed block for each element in the collection.

    ["Alice", "Bob"].sum(1) { |name| name.size } # => 9 (1 + 5 + 3)

Expects all types returned from the block to respond to `#+` method.

If the collection is empty, returns initial.

    ([] of String).sum(1) { |name| name.size } # => 1

def sum(& : T -> ) #

Adds all results of the passed block for each element in the collection.

    ["Alice", "Bob"].sum { |name| name.size } # => 8 (5 + 3)

Expects all types returned from the block to respond to `#+` method.

This method calls `.additive_identity` on the yielded type to determine the type of the sum value. Hence, it can fail to compile if `.additive_identity` fails to determine a safe type, e.g., in case of union types. In such cases, use `#sum(initial)` with an initial value of the expected type of the sum value.

If the collection is empty, returns `additive_identity`.

    ([] of Int32).sum { |x| x + 1 } # => 0

def take_while(& : T -> ) : Array(T) #

Passes elements to the block until the block returns a falsey value, then stops iterating and returns an `Array` of all prior elements.

    [1, 2, 3, 4, 5, 0].take_while { |i| i < 3 } # => [1, 2]

def tally(hash) #

Tallies the collection. Accepts a hash to count occurrences. The value corresponding to each element must be an integer. The number of occurrences is added to each value in hash, and hash is returned.

    hash = {} of Char => Int32
    words = ["crystal", "ruby"]
    words.each { |word| word.chars.tally(hash) }
    hash # => {'c' => 1, 'r' => 2, 'y' => 2, 's' => 1, 't' => 1, 'a' => 1, 'l' => 1, 'u' => 1, 'b' => 1}

def tally : Hash(T, Int32) #

Tallies the collection. Returns a hash where the keys are the elements and the values are numbers of elements in the collection that correspond to the key.

    ["a", "b", "c", "b"].tally # => {"a"=>1, "b"=>2, "c"=>1}

def tally_by(hash, &) #

Tallies the collection. Accepts a hash to count occurrences. The value corresponding to each element must be an integer. Returns hash where the keys are the elements and the values are numbers of elements in the collection that correspond to the key after transformation by the given block.

    hash = {} of Char => Int32
    words = ["Crystal", "Ruby"]
    words.each { |word| word.chars.tally_by(hash, &.downcase) }
    hash # => {'c' => 1, 'r' => 2, 'y' => 2, 's' => 1, 't' => 1, 'a' => 1, 'l' => 1, 'u' => 1, 'b' => 1}

def tally_by(&block : T -> U) : Hash(U, Int32) forall U #

Tallies the collection. Returns a hash where the keys are the elements and the values are numbers of elements in the collection that correspond to the key after transformation by the given block.

    ["a", "A", "b", "B"].tally_by(&.downcase) # => {"a" => 2, "b" => 2}

def to_a : Array(T) #

Returns an `Array` with all the elements in the collection.

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

def to_a(& : T -> U) : Array(U) forall U #

Returns an `Array` with the results of running block against each element of the collection.

    (1..5).to_a { |i| i * 2 } # => [2, 4, 6, 8, 10]

def to_h #

Creates a `Hash` out of an Enumerable where each element is a 2 element structure (for instance a `Tuple` or an `Array`).

    [[:a, :b], [:c, :d]].to_h        # => {:a => :b, :c => :d}
    Tuple.new({:a, 1}, {:c, 2}).to_h # => {:a => 1, :c => 2}

def to_h(& : T -> Tuple(K, V)) forall K, V #

Creates a `Hash` out of `Tuple` pairs (key, value) returned from the block.

    (1..3).to_h { |i| {i, i ** 2} } # => {1 => 1, 2 => 4, 3 => 9}

def to_set : Set(T) #

Returns a new `Set` with each unique element in the enumerable.

def to_set(&block : T -> U) : Set(U) forall U #

Returns a new `Set` with the unique results of running block against each element of the enumerable.

def zip(*others : Indexable | Iterable | Iterator, &) #

Yields elements of `self` and others in tandem to the given block.

Raises an `IndexError` if any of others doesn't have as many elements as `self`. See `#zip?` for a version that yields `nil` instead of raising.

    a = [1, 2, 3]
    b = ["a", "b", "c"]

    a.zip(b) { |x, y| puts "#{x} -- #{y}" }

The above produces:

    1 -- a
    2 -- b
    3 -- c

An example with multiple arguments:

    (1..3).zip(4..6, 7..9) do |x, y, z|
      puts "#{x} -- #{y} -- #{z}"
    end

The above produces:

    1 -- 4 -- 7
    2 -- 5 -- 8
    3 -- 6 -- 9

def zip(*others : Indexable | Iterable | Iterator) #

Returns an `Array` of tuples populated with the elements of `self` and others traversed in tandem.

Raises an `IndexError` if any of others doesn't have as many elements as `self`. See `#zip?` for a version that yields `nil` instead of raising.

    a = [1, 2, 3]
    b = ["a", "b", "c"]

    a.zip(b) # => [{1, "a"}, {2, "b"}, {3, "c"}]

An example with multiple arguments:

    a = [1, 2, 3]
    b = (4..6)
    c = 8.downto(3)

    a.zip(b, c) # => [{1, 4, 8}, {2, 5, 7}, {3, 6, 6}]

def zip?(*others : Indexable | Iterable | Iterator, &) #

Yields elements of `self` and others in tandem to the given block.

All of the elements in `self` will be yielded: if others don't have that many elements they will be returned as `nil`.

    a = [1, 2, 3]
    b = ["a", "b"]

    a.zip?(b) { |x, y| puts "#{x.inspect} -- #{y.inspect}" }

The above produces:

    1 -- "a"
    2 -- "b"
    3 -- nil

An example with multiple arguments:

    (1..3).zip?(4..5, 7..8) do |x, y, z|
      puts "#{x.inspect} -- #{y.inspect} -- #{z.inspect}"
    end

The above produces:

    1 -- 4 -- 7
    2 -- 5 -- 8
    3 -- nil -- nil

def zip?(*others : Indexable | Iterable | Iterator) #

Returns an `Array` of tuples populated with the elements of `self` and others traversed in tandem.

All elements in `self` are returned in the Array. If matching elements in others are missing (because they don't have that many elements) `nil` is returned inside that tuple index.

    a = [1, 2, 3]
    b = ["a", "b"]

    a.zip?(b) # => [{1, "a"}, {2, "b"}, {3, nil}]

An example with multiple arguments:

    a = [1, 2, 3]
    b = (4..5)
    c = 8.downto(7)

    a.zip?(b, c) # => [{1, 4, 8}, {2, 5, 7}, {3, nil, nil}]