Today’s Ruby Tuesday covers Enumerable#zip.
Enumerable#zip
weaves together elements of multiple Enumerable
s. It iterates through each item in the enum and combines it with the corresponding element from each of the arguments passed to zip, resulting in an array of arrays.
[:a, :b, :c].zip([1, 2, 3]) # => [[:a, 1], [:b, 2], [:c, 3]] [:a, :b, :c].zip([1, 2, 3], [:foo, :bar, :baz]) # => [[:a, 1, :foo], [:b, 2, :bar], [:c, 3, :baz]]
If an item in the argument list is shorter then the enum that zip
is being called on, nil
is used where the item would have been added.
[:a, :b, :c].zip([1], [:foo, :bar, :baz, :snafu]) # => [[:a, 1, :foo], [:b, nil, :bar], [:c, nil, :baz]]
The length of the returned array is the length of the enum that zip
is being called on. Any extra elements in the enumerable passed to zip
are ignored, and if are in a lazy enumerble not computed.
[:a, :b, :c].zip([1, 2, 3, 4], [:foo, :bar, :baz, :snafu]) # => [[:a, 1, :foo], [:b, 2, :bar], [:c, 3, :baz]] ### Only takes what is needed ### require 'benchmark' # => true Benchmark.measure do [:a, :b].zip( (1..1_000_000_000_000).lazy.map{|x| x*x*x} ) end # => #<Benchmark::Tms:0x007fd5749d9288 # @cstime=0.0, # @cutime=0.0, # @label="", # @real=4.3e-05, # @stime=0.0, # @total=0.0, # @utime=0.0> #### For much much less, took 8+ seconds #### Benchmark.measure do [:a, :b].zip( (1..10_000_000).map{|x| x*x*x} ) end # => #<Benchmark::Tms:0x007faed4779e00 # @cstime=0.0, # @cutime=0.0, # @label="", # @real=8.616259, # @stime=0.7200000000000002, # @total=8.53, # @utime=7.809999999999999>
Enumerable#zip
can also be given a block. If a block is provided, the combined array of items is passed to the block, and not returned as a result. This behavior is distinct from Enumerable#each
in that each
still returns the Enumerable it was invoked on, where as zip
returns nil
as it’s result when a block is given.
[:a, :b, :c].zip([1, 2, 3, 4], [:foo, :bar, :baz, :snafu]) { |items| puts items.to_s } # [:a, 1, :foo] # [:b, 2, :bar] # [:c, 3, :baz] # => nil [:a, :b, :c].zip([1, 2, 3, 4], [:foo, :bar, :baz, :snafu]).each { |items| puts items.to_s } # [:a, 1, :foo] # [:b, 2, :bar] # [:c, 3, :baz] # => [[:a, 1, :foo], [:b, 2, :bar], [:c, 3, :baz]]
–Proctor