Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining Streams of substrings

I have the following code that iterates over Java DateTimeFormatter pattern combinations of "E".."EEEE" and "M".."MMMM".

My question is, is there an idiomatic (or just 'more idiomatic') way to use Java Streams in this case?

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class DateTimeFormattingStackOverflow {
    static LocalDateTime dateTime = LocalDateTime.now();

    static Stream<String> substrings(String str) {
        return IntStream.range(1, str.length() + 1)
                .mapToObj(i -> str.substring(0, i));
    }

    static void printDateTime(String pattern) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern);
        System.out.println(pattern + ", " + dtf.format(dateTime));
    }

    public static void main(String[] args) {
        Stream<String> patterns = substrings("EEEE")
                .flatMap(e -> substrings("MMMM").map(m -> e + " " + m))
                .map(em -> em + " d");

        patterns.forEach(DateTimeFormattingStackOverflow::printDateTime);
    }
}

Output

E M d, Sat 7 1
E MM d, Sat 07 1
E MMM d, Sat Jul 1
E MMMM d, Sat July 1
EE M d, Sat 7 1
EE MM d, Sat 07 1
EE MMM d, Sat Jul 1
EE MMMM d, Sat July 1
...
like image 224
Paul Grime Avatar asked Jul 01 '17 11:07

Paul Grime


People also ask

How do I merge two streams?

Stream. concat() method creates a concatenated stream in which the elements are all the elements of the first stream followed by all the elements of the second stream. The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel. The calls to Stream.

How do you join a stream of strings?

Join stream of strings – examplejoining() method takes separator string as argument and join all the strings in the stream using using this separator. For example, we use comma as separator then this method will result into a comma-separated string. Program output.

What is stream forEach?

Stream forEach(Consumer action) performs an action for each element of the stream. Stream forEach(Consumer action) is a terminal operation i.e, it may traverse the stream to produce a result or a side-effect.


1 Answers

You are using an IntStream to drive the string. That's one way to do it, and here are two other ways:

static Stream<String> substrings(String str) {
    return str.length() == 1 ? Stream.of(str) :
            Stream.concat(Stream.of(str), substrings(str.substring(1)));
}

This creates a Stream recursively, while the other way would be as follows:

static Stream<String> substrings2(String str) {
    return Stream.iterate(str, s -> s.substring(1)).limit(str.length());
}

This applies the given function to the previous result. As it creates an infinite stream, you have to use limit.

I have slightly modified your main method, so that you avoid one map operation:

substrings("EEEE")
    .flatMap(e -> substrings("MMMM").map(m -> e + " " + m + " d"))
    .forEach(DateTimeFormattingStackOverflow::printDateTime);

I really don't know if the ways above are more or less idiomatic than your way, but if you ask me, the most idiomatic way to do this task is with a nested loop:

String e = "EEEE";
String m = "MMMM";

for (int i = 0; i < e.length(); i++)
    for (int j = 0; j < m.length(); j++)
        printDateTime(e.substring(i) + " " + m.substring(j) + " d");

And this might be translated to Java 8 as follows:

IntStream.range(0, e.length()).boxed()
    .flatMap(i -> IntStream.range(0, m.length())
        .mapToObj(j -> e.substring(i) + " " + m.substring(j) + " d"))
    .forEach(DateTimeFormattingStackOverflow::printDateTime);
like image 60
fps Avatar answered Sep 19 '22 18:09

fps