Collections - Infinite Lists

How is it done in Haskell?

If you don’t specify the upper limit, it will be an infinite list.

e.g. How will you get the first 24 multiples of 13? other than doing [13,26..24*13]

take 24 [13, 26..]
[13,26,39,52,65,78,91,104,117,130,143,156,169,182,195,208,221,234,247,260,273,286,299,312]

Here are a handful of collections that produce infinite lists..

cycle takes a list and cycles it into an infinite list. If you just try to display the result, it will go on forever so you have to slice it off somewhere.

take 10 (cycle [1,2,3])
take 12 (cycle "LOL ")
[1,2,3,1,2,3,1,2,3,1]
LOL LOL LOL

repeat takes an element and produces an infinite list of just that element. It’s like cycling a list with only one element.

take 10 (repeat 5)
[5,5,5,5,5,5,5,5,5,5]

Use the replicate function if you want a finite list with the same element in the list.

replicate 3 10
[10,10,10]

Infinite lists in Java

How to generate an infinite list and java take n elements out of that infinite list?

Java doesn’t have a built-in “infinite list” data structure in the way some functional languages might. Instead, you represent an “infinite” sequence by having a way to generate the next element on demand.

The most common ways to do this in Java are:

  1. Using java.util.function.Supplier<T>: A supplier can provide an endless stream of values.
  2. Using java.util.stream.Stream.generate() or Stream.iterate(): These methods from the Stream API are designed for creating potentially infinite streams.
  3. Using a custom Iterator<T>: An iterator where hasNext() always returns true and next() generates the subsequent element.

Then, to “take n elements,” you simply generate and collect the first n elements.

Key Takeaways

  1. No True Infinite Data Structure
    1. You don’t store infinite elements; you generate them.
  2. On-Demand Generation
    1. Elements are created only when requested.
  3. Supplier<T>
    1. A simple functional interface for providing values.
  4. Java Streams
    1. The Stream.generate() and Stream.iterate() methods are powerful tools for creating sequences, which can then be limited using limit(n). This is generally the preferred modern approach.
  5. Iterator<T>
    1. A more traditional way, but requires ensuring hasNext() behaves as expected for an “infinite” source.
  6. limit(n)
    1. The crucial operation that turns an infinite generation process into a finite result.

Choose the method that best fits your needs and coding style. For new code, the Stream API (Method 2) is often the most expressive and concise.

Here are examples for each approach:

Method 1: Using Supplier<T> and a loop

See https://github.com/explorer436/programming-playground/blob/main/java-playground/my-java-solutions/src/main/java/com/my/company/numbers/TakeNFromInfiniteIteratorUsingForLoop.java

Method 2: Using Java Streams (Stream.generate() or Stream.iterate())

This is often the most idiomatic and concise way in modern Java (Java 8+).

See https://github.com/explorer436/programming-playground/blob/main/java-playground/my-java-solutions/src/main/java/com/my/company/numbers/TakeNFromInfiniteSupplierUsingStreamLimit.java

Method 3: Using a custom Iterator<T>

See https://github.com/explorer436/programming-playground/blob/main/java-playground/my-java-solutions/src/main/java/com/my/company/numbers/TakeNFromInfiniteIteratorUsingForLoop.java


Links to this note