Search

Dark theme | Light theme

September 26, 2025

Groovy Goodness: Grouping Iterables Using zip And zipAll

Groovy 5 adds the extension methods zip and zipAll for iterables and iterators. Using the method you can combine elements from two collections into a new collection. The new collection contains Tuple2 instances where the values come from the items at the same index from both collections. So the first item of the first collection is grouped with the first item of the second collection. The size of the resulting collection is determined by the size of the smallest collection that is zipped.
With the zipAll method you can combine iterables of different sizes and set default values for missing items. It is possible to set a default value if an item is missing from the first iterable or the second iterable.

In the following example several uses of the zip and zipAll methods are shown:

import static groovy.lang.Tuple.tuple

def numbers = 1..4
def letters = 'a'..'d'

// Equals size iterables result in same number
// of Tuple2 instances.
assert numbers.zip(letters) == [tuple(1, 'a'),
                                tuple(2, 'b'),
                                tuple(3, 'c'),
                                tuple(4, 'd')]

// With uneven sized iterables the one with least number
// of items is used to determine the number of Tuple2 instances
// in the result.
assert (1..3).zip(letters) == [tuple(1, 'a'),
                               tuple(2, 'b'),
                               tuple(3, 'c')]

assert numbers.zip('a'..'c') == [tuple(1, 'a'),
                                 tuple(2, 'b'),
                                 tuple(3, 'c')]

// If the iterables are not the same size
// you can use zipAll and define values to
// use to fill up the result.
assert (1..3).zipAll(letters, 'default', _) == [tuple(1, 'a'),
                                                tuple(2, 'b'),
                                                tuple(3, 'c'),
                                                tuple('default', 'd')]
assert numbers.zipAll('a'..'c', _, 'default') == [tuple(1, 'a'),
                                                  tuple(2, 'b'),
                                                  tuple(3, 'c'),
                                                  tuple(4, 'default')]

// The zip and zipAll also work for iterators.
// The result is a ZipIterator instance so you need
// to materialize the iterator to get the actual result.
assert numbers.iterator().zip(letters.iterator())
                         .toList() == [tuple(1, 'a'),
                                       tuple(2, 'b'),
                                       tuple(3, 'c'),
                                       tuple(4, 'd')]
assert (1..3).iterator().zipAll(letters.iterator(), 'default', _)
                        .toList() == [tuple(1, 'a'),
                                      tuple(2, 'b'),
                                      tuple(3, 'c'),
                                      tuple('default', 'd')]

Written with Groovy 5.0.0.