W3cubDocs

/Crystal

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

Defined in:

enumerable.cr
set.cr

Instance Method Summary

Instance Method Detail

def all?(&)Source

Returns true if the passed block returns a value other than false or nil 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)Source

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?Source

Returns true if none of the elements of the collection is false or nil.

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

def any?(&)Source

Returns true if the passed block returns a value other than false or nil 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)Source

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?Source

Returns true if at least one of the collection members is not false or nil.

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

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

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:

See also: Iterator#chunk.

def compact_map(&)Source

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(&)Source

Returns the number of elements in the collection for which the passed block returns true.

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

def count(item)Source

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

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

def cycle(&)Source

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

def cycle(n, &)Source

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

abstract def each(&block : T -> _)Source

Must yield this collection's elements to the block.

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

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 size == 2 which avoids heap allocations.

def each_cons_pair(& : T, T -> _) : NilSource

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 size == 2 to avoid heap allocations.

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

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_with_index(offset = 0, &)Source

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, &)Source

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?Source

Returns true if self is empty, false otherwise.

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

def find(if_none = nil, &)Source

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

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 first(&)Source

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

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 firstSource

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?Source

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(&block : T -> Array(U) | Iterator(U) | U) forall USource

Returns a new array with the concatenated results of running the block (which is expected to return arrays) once for every element in the collection.

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

def grep(pattern)Source

Returns an Array with all the elements in the collection that match the RegExp pattern.

["Alice", "Bob"].grep(/^A/) # => ["Alice"]

DEPRECATED Use #select instead

def group_by(&block : T -> U) forall USource

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 USource

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 USource

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 includes?(obj)Source

Returns true if the collection contains obj, false otherwise.

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

def index(&)Source

Returns the index of the first element for which the passed block returns true.

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

Returns nil if the block didn't return true for any element.

def index(obj)Source

Returns the index of the object obj in the collection.

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

Returns nil if obj is not in the collection.

def index_by(&block : T -> U) forall USource

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(separator = "", & : T -> )Source

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 join(separator, io : IO, &)Source

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(io : IO, separator = "", & : T, IO -> )Source

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 = "")Source

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(separator, io : IO)Source

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(io : IO, separator = "")Source

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 map(&block : T -> U) forall USource

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, &block : T, Int32 -> U) forall USource

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 maxSource

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?Source

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

def max_by(&block : T -> U) forall USource

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?(&block : T -> U) forall USource

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

def max_of(&block : T -> U) forall USource

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?(&block : T -> U) forall USource

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

def minSource

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?Source

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

def min_by(&block : T -> U) forall USource

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?(&block : T -> U) forall USource

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

def min_of(&block : T -> U) forall USource

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?(&block : T -> U) forall USource

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

def minmaxSource

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?Source

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

def minmax_by(&block : T -> U) forall USource

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?(&block : T -> U) forall USource

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

def minmax_of(&block : T -> U) forall USource

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?(&block : T -> U) forall USource

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

def none?Source

Returns true if all of the elements of the collection are false or nil.

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

It's the opposite of #all?.

def none?(pattern)Source

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?(&)Source

Returns true if the passed block returns true for none of the elements of the collection.

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

It's the opposite of #all?.

def one?(&)Source

Returns true if the passed block returns true 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)Source

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?Source

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(&)Source

Returns a Tuple with two arrays. The first one contains the elements in the collection for which the passed block returned true, and the second one those for which it returned false.

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

def productSource

Multiplies all the elements in the collection together.

Only collections of numbers (objects that can be multiplied via a * method) are supported.

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

If the collection is empty, returns 1.

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

def product(initial : Number)Source

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.

Only collections of numbers (objects that can be multiplied via a * method) are supported.

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

If the collection is empty, returns initial.

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

def product(initial : Number, &)Source

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)

If the collection is empty, returns 1.

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

def product(&)Source

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

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

If the collection is empty, returns 1.

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

def reduce(memo, &)Source

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(&)Source

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.

[1, 2, 3, 4, 5].reduce { |acc, i| acc + i } # => 15

def reduce?(&)Source

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

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

def reject(pattern)Source

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 reject(type : U.class) forall USource

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(&block : T -> )Source

Returns an Array with all the elements in the collection for which the passed block returns false.

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

def select(pattern)Source

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 select(type : U.class) forall USource

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(&block : T -> )Source

Returns an Array with all the elements in the collection for which the passed block returns true.

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

def sizeSource

Returns the number of elements in the collection.

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

def skip(count : Int)Source

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(&)Source

Skips elements up to, but not including, the first element for which the block returns nil or false 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)Source

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.

Only collections of numbers (objects that can be added via an + method) are supported.

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

If the collection is empty, returns initial.

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

def sumSource

Adds all the elements in the collection together.

Only collections of numbers (objects that can be added via an + method) are supported.

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

If the collection is empty, returns 0.

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

def sum(initial, &)Source

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)

If the collection is empty, returns 0.

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

def sum(&)Source

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

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

If the collection is empty, returns 0.

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

def take_while(&)Source

Passes elements to the block until the block returns nil or false, 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(T, Int32)Source

Tallys 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 to_aSource

Returns an Array with all the elements in the collection.

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

def to_hSource

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(&block : T -> Tuple(K, V)) forall K, VSource

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_setSource

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

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

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

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, &)Source

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

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

© 2012–2020 Manas Technology Solutions.
Licensed under the Apache License, Version 2.0.
https://crystal-lang.org/api/0.35.1/Enumerable.html