Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generator functions equivalent in Java

I would like to implement an Iterator in Java that behaves somewhat like the following generator function in Python:

def iterator(array):    for x in array:       if x!= None:         for y in x:           if y!= None:             for z in y:               if z!= None:                 yield z 

x on the java side can be multi-dimensional array or some form of nested collection. I am not sure how this would work. Ideas?

like image 372
Eqbal Avatar asked Jul 19 '12 22:07

Eqbal


People also ask

What is a generator function in Java?

In simple terms, a generator is a function which returns the next value in a sequence. Unlike an iterator, it generates the next value when needed, rather than returning the next item of a pre-generated collection. Some languages such as Python support generators natively via keywords such as yield.

What is generator and iterator in Java?

Iterators are used mostly to iterate or convert other objects to an iterator using iter() function. Generators are mostly used in loops to generate an iterator by returning all the values in the loop without affecting the iteration of the loop. Iterator uses iter() and next() functions.

Does Java have yield?

Several programming languages, such as Ruby or Python to name a few, provides the yield command. Yield provides an effective way, in terms of memory consumption, to create series of values, by generating such values on demand.

What is difference between generator and normal function?

Generator Functions are memory efficient, as they save a lot of memory while using generators. A normal function will return a sequence of items, but before giving the result, it creates a sequence in memory and then gives us the result, whereas the generator function produces one output at a time.


2 Answers

Had the same need so wrote a little class for it. Here are some examples:

Generator<Integer> simpleGenerator = new Generator<Integer>() {     public void run() throws InterruptedException {         yield(1);         // Some logic here...         yield(2);     } }; for (Integer element : simpleGenerator)     System.out.println(element); // Prints "1", then "2". 

Infinite generators are also possible:

Generator<Integer> infiniteGenerator = new Generator<Integer>() {     public void run() throws InterruptedException {         while (true)             yield(1);     } }; 

The Generator class internally works with a Thread to produce the items. By overriding finalize(), it ensures that no Threads stay around if the corresponding Generator is no longer used.

The performance is obviously not great but not too shabby either. On my machine with a dual core i5 CPU @ 2.67 GHz, 1000 items can be produced in < 0.03s.

The code is on GitHub. There, you'll also find instructions on how to include it as a Maven/Gradle dependency.

like image 129
Michael Herrmann Avatar answered Sep 21 '22 20:09

Michael Herrmann


Indeed Java has no yield, but you can now use Java 8 streams. IMO it's really a complicated iterator since it's backed by an array, not a function. Given it's a loop in a loop in a loop can be expressed as a Stream using filter (to skip the nulls) and flatMap to stream the inner collection. It's also about the size of the Python code. I've converted it to an iterator to use at your leisure and printed to demonstrate, but if all you were doing was printing, you could end the stream sequence with forEach(System.out::println) instead of iterator().

public class ArrayIterate {     public static void main(String args[])     {         Integer[][][] a = new Integer[][][] { { { 1, 2, null, 3 },                                                 null,                                                 { 4 }                                               },                                               null,                                               { { 5 } } };          Iterator<Object> iterator = Arrays.stream(a)                                           .filter(ax -> ax != null)                                           .flatMap(ax -> Arrays.stream(ax)                                                .filter(ay -> ay != null)                                                .flatMap(ay -> Arrays.stream(ay)                                                .filter(az -> az != null)))                                           .iterator();          while (iterator.hasNext())         {             System.out.println(iterator.next());         }     } } 

I'm writing about implementation of generators as part of my blog on Java 8 Functional Programming and Lambda Expressions at http://thecannycoder.wordpress.com/ which might give you some more ideas for converting Python generator functions into Java equivalents.

like image 25
TheCannyCoder Avatar answered Sep 22 '22 20:09

TheCannyCoder