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