Hi folks,

We have done some work in DefaultGroovyMethods and ArrayGroovyMethods
in Groovy 5 to improve performance. There is one area which I think
would still be useful to attend to and that is various use cases of
transpose(). This method is really handy but creates additional
aggregates (lists or arrays) when oftentimes, these are just going to
be iterated in subsequent steps. This consumes time and memory for
large aggregates. This is streams territory in some sense, but
particularly within ArrayGroovyMethods, our extension methods have
numerous advantages over streams in certain circumstances. So, I'd
like to propose a "zip" method and a "columns" method.

I'd only propose zipping 2 aggregates initially. Some
languages/libraries support more aggregates but we already have
transpose and we can always add more variants if zip proves popular.
The zip method returns an iterator, so:

[listA, listB].transpose().xxx()

is the same as:

listA.zip(listB).xxx()

but uses an iterator rather than creating new lists.

Here's some examples:

def one = ['cat', 'spider']
def two = ['fish', 'monkey']
assert ['catfish', 'spidermonkey'] == one.zip(two).collect{ a, b -> a + b }
assert one.zip(two).any{ a, b -> a.size() == b.size() }
assert !one.zip(two).every{ a, b -> a.size() == b.size() }
//   equivalent:
//assert ['catfish', 'spidermonkey'] == [one,
two].transpose().collect{ a, b -> a + b }
//assert [one, two].transpose().any{ a, b -> a.size() == b.size() }
//assert ![one, two].transpose().every{ a, b -> a.size() == b.size() }

int[] small = [1, 2, 3]
int[] large = [100, 200, 300]
assert [101, 202, 303] == small.zip(large).collect{ a, b -> a + b }
//   equivalent:
//assert [101, 202, 303] == [small, large].transpose().collect{ a, b -> a + b }

The other use case is avoiding transpose for large 2D arrays when all
you want is traversal. For that I propose a column iterator:

int[][] nums = [[1, 2, 3],
                [10, 20, 30],
                [100, 200, 300],
                [1000, 2000, 3000]]

assert [6, 60, 600, 6000] == nums.collect{ int[] row -> row.sum() }
assert [1111, 2222, 3333] == nums.columns().collect{ int[] col -> col.sum() }
//    equivalent:
//assert [1111, 2222, 3333] == nums.transpose().collect{ int[] row ->
row.sum() }

I welcome feedback, but I'll create a PR in the next couple of days,
so you can also wait and give feedback on that if you prefer.

Cheers, Paul.

Reply via email to