[ 
https://issues.apache.org/jira/browse/GROOVY-11603?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Paul King updated GROOVY-11603:
-------------------------------
    Description: 
This issue is to propose some iterate, generate and combine methods. The first 
two are exact mirrors of their Stream counterparts.
{code:groovy}
def evens = Iterators.iterate(2, n -> n + 2)
def odds = Iterators.iterate(1, n -> n + 2)
assert evens.take(4).collect() == [2, 4, 6, 8]
assert odds.take(4).collect() == [1, 3, 5, 7]

var r = new Random()
var randomDigits = Iterators.generate({ r.nextInt(10) } as Supplier)
println randomDigits.take(10).join() // 2698715440 (different every time)
assert randomDigits.take(3).collect() ==~ /\[\d, \d, \d\]/ // regex of 3 digits
{code}
We could achieve the same result using the Streams API as follows:
{code:groovy}
def alsoEvens = Stream.iterate(2, n -> n + 2).iterator()
assert alsoEvens.take(4).collect() == [2, 4, 6, 8]
{code}
So, these two methods are "just" convenience without the overhead of setting up 
the Stream, so will be quicker for many simple cases.

The other methods are combine and combineLazy. They are iterator variants of 
combinations/eachCombination with some inspiration from the Groovy-stream 
project to use a map to name the streams/result tuples. This is also known as 
cross-product and Groovy-stream calls dubs its take on cross product as faux 
list-comprehension which is something we have wanted for a while.
{code:groovy}
assert Iterators.combine(x: 1..2, y: 'a'..'c').collect().toString()
    == '[[x:1, y:a], [x:1, y:b], [x:1, y:c], [x:2, y:a], [x:2, y:b], [x:2, 
y:c]]'
assert Iterators.combine(x: 1..3, y: 'a'..'b').collect().toString()
    == '[[x:1, y:a], [x:1, y:b], [x:2, y:a], [x:2, y:b], [x:3, y:a], [x:3, 
y:b]]'
{code}
The combineLazy method is the same but expects iterators as the input sources 
not iterables. The traditional cross-product output would not be very 
interesting if there are two or more infinite streams as the sources as can be 
seen from the first of the next two examples (even is always 0). So, there is 
an optional flag, fairOrder, which visits the streams one index level at a 
time, (sort of breadth first vs depth first).
{code:groovy}
assert Iterators.combineLazy(
    even: Iterators.iterate(0, n -> n + 2),
    odd: Iterators.iterate(1, n -> n + 2), false)
    .take(10).collect().join('\n')
    == '''
[even:0, odd:1]
[even:0, odd:3]
[even:0, odd:5]
[even:0, odd:7]
[even:0, odd:9]
[even:0, odd:11]
[even:0, odd:13]
[even:0, odd:15]
[even:0, odd:17]
[even:0, odd:19]
'''.trim()

assert Iterators.combineLazy(
    even: Iterators.iterate(0, n -> n + 2),
    odd: Iterators.iterate(1, n -> n + 2), true)
    .take(10).collect().join('\n')
    == '''
[even:0, odd:1]
[even:0, odd:3]
[even:2, odd:1]
[even:2, odd:3]
[even:0, odd:5]
[even:2, odd:5]
[even:4, odd:1]
[even:4, odd:3]
[even:4, odd:5]
[even:0, odd:7]
'''.trim()
{code}
There are some more things to think about to fully utilise some of the 
functionality from Groovy-stream but these cross product generators seem like a 
nice start.

> Add Lazy generators for iterators
> ---------------------------------
>
>                 Key: GROOVY-11603
>                 URL: https://issues.apache.org/jira/browse/GROOVY-11603
>             Project: Groovy
>          Issue Type: Improvement
>            Reporter: Paul King
>            Assignee: Paul King
>            Priority: Major
>
> This issue is to propose some iterate, generate and combine methods. The 
> first two are exact mirrors of their Stream counterparts.
> {code:groovy}
> def evens = Iterators.iterate(2, n -> n + 2)
> def odds = Iterators.iterate(1, n -> n + 2)
> assert evens.take(4).collect() == [2, 4, 6, 8]
> assert odds.take(4).collect() == [1, 3, 5, 7]
> var r = new Random()
> var randomDigits = Iterators.generate({ r.nextInt(10) } as Supplier)
> println randomDigits.take(10).join() // 2698715440 (different every time)
> assert randomDigits.take(3).collect() ==~ /\[\d, \d, \d\]/ // regex of 3 
> digits
> {code}
> We could achieve the same result using the Streams API as follows:
> {code:groovy}
> def alsoEvens = Stream.iterate(2, n -> n + 2).iterator()
> assert alsoEvens.take(4).collect() == [2, 4, 6, 8]
> {code}
> So, these two methods are "just" convenience without the overhead of setting 
> up the Stream, so will be quicker for many simple cases.
> The other methods are combine and combineLazy. They are iterator variants of 
> combinations/eachCombination with some inspiration from the Groovy-stream 
> project to use a map to name the streams/result tuples. This is also known as 
> cross-product and Groovy-stream calls dubs its take on cross product as faux 
> list-comprehension which is something we have wanted for a while.
> {code:groovy}
> assert Iterators.combine(x: 1..2, y: 'a'..'c').collect().toString()
>     == '[[x:1, y:a], [x:1, y:b], [x:1, y:c], [x:2, y:a], [x:2, y:b], [x:2, 
> y:c]]'
> assert Iterators.combine(x: 1..3, y: 'a'..'b').collect().toString()
>     == '[[x:1, y:a], [x:1, y:b], [x:2, y:a], [x:2, y:b], [x:3, y:a], [x:3, 
> y:b]]'
> {code}
> The combineLazy method is the same but expects iterators as the input sources 
> not iterables. The traditional cross-product output would not be very 
> interesting if there are two or more infinite streams as the sources as can 
> be seen from the first of the next two examples (even is always 0). So, there 
> is an optional flag, fairOrder, which visits the streams one index level at a 
> time, (sort of breadth first vs depth first).
> {code:groovy}
> assert Iterators.combineLazy(
>     even: Iterators.iterate(0, n -> n + 2),
>     odd: Iterators.iterate(1, n -> n + 2), false)
>     .take(10).collect().join('\n')
>     == '''
> [even:0, odd:1]
> [even:0, odd:3]
> [even:0, odd:5]
> [even:0, odd:7]
> [even:0, odd:9]
> [even:0, odd:11]
> [even:0, odd:13]
> [even:0, odd:15]
> [even:0, odd:17]
> [even:0, odd:19]
> '''.trim()
> assert Iterators.combineLazy(
>     even: Iterators.iterate(0, n -> n + 2),
>     odd: Iterators.iterate(1, n -> n + 2), true)
>     .take(10).collect().join('\n')
>     == '''
> [even:0, odd:1]
> [even:0, odd:3]
> [even:2, odd:1]
> [even:2, odd:3]
> [even:0, odd:5]
> [even:2, odd:5]
> [even:4, odd:1]
> [even:4, odd:3]
> [even:4, odd:5]
> [even:0, odd:7]
> '''.trim()
> {code}
> There are some more things to think about to fully utilise some of the 
> functionality from Groovy-stream but these cross product generators seem like 
> a nice start.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to