Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most idiomatic way to create cycled and infinite range of integers in Java 8

In ruby you can do something like this

a = ["a", "b", "c"]
a.cycle {|x| puts x }  # print, a, b, c, a, b, c,.. forever.
a.cycle(2) {|x| puts x }  # print, a, b, c, a, b, c.

and this is just beautiful.

The closest analog in Java 8 would be like this:

Stream<Integer> iterator = Stream.iterate(new int[] {0, 0}, p -> new int[]{p[0] + 1, (p[0] + 1) % 2}).map(el -> el[1]);
Iterator<Integer> iter = iterator.iterator();
System.out.println(iter.next());//0
System.out.println(iter.next());//1
System.out.println(iter.next());//0
System.out.println(iter.next());//1

Is there a better way and more idiomatic to do it in Java?

Update

Just want to outline here that the closest solution to my problem was

IntStream.generate(() -> max).flatMap(i -> IntStream.range(0, i)) 

Thanks to @Hogler

like image 754
Igor Wiwi Avatar asked Jan 28 '23 12:01

Igor Wiwi


2 Answers

You may use

String[] array = { "a", "b", "c" };
Stream.generate(() -> array).flatMap(Arrays::stream).forEach(System.out::println);

to print a b c forever and

String[] array = { "a", "b", "c" };
Stream.generate(() -> array).limit(2).flatMap(Arrays::stream).forEach(System.out::println);

to print a b c two times.

This doesn’t even require an existing array:

Stream.generate(() -> null)
      .flatMap(x -> Stream.of("a", "b", "c"))
      .forEach(System.out::println);

resp.

Stream.generate(() -> null).limit(2)
      .flatMap(x -> Stream.of("a", "b", "c"))
      .forEach(System.out::println);

you could also use

IntStream.range(0, 2).boxed()
      .flatMap(x -> Stream.of("a", "b", "c"))
      .forEach(System.out::println);
like image 181
Holger Avatar answered Jan 31 '23 00:01

Holger


Well if you define the array variable outside the stream, you can use indexes instead. And you will have something like:

String[] array = { "a", "b", "c" };

Stream.iterate(0, i -> (i + 1) % array.length)
        .map(i -> array[i])
        .forEach(System.out::println); // prints a, b, c forever

Stream.iterate(0, i -> (i + 1) % array.length)
        .map(i -> array[i])
        .limit(2 * array.length)
        .forEach(System.out::println); // prints a, b, c 2 times

Also can use nCopies you don't need to use array.length:

Collections.nCopies(2, array).stream()
        .flatMap(Arrays::stream)
        .forEach(System.out::println); // prints a, b, c 2 times

It is obviously longer than the ruby version, but that's how usually java is (more verbose)

like image 29
Jose Da Silva Avatar answered Jan 31 '23 02:01

Jose Da Silva