Skip to main content
added 122 characters in body
Source Link
Tunaki
  • 9.3k
  • 1
  • 30
  • 46

That brings also a big advantage: the method is returning a Stream<String>, that is to say, the method does not actually perform the calculation. It is then up-to the caller to decide when to do it and, if they want it to happen in parallel or not, and especially what the end container will be (a List, a Set, no container at all with just post-processing afterwards).

That brings also a big advantage: the method is returning a Stream<String>, that is to say, the method does not actually perform the calculation. It is then up-to the caller to decide when to do it and if they want it to happen in parallel or not.

That brings also a big advantage: the method is returning a Stream<String>, that is to say, the method does not actually perform the calculation. It is then up-to the caller to decide when to do it, if they want it to happen in parallel or not, and especially what the end container will be (a List, a Set, no container at all with just post-processing afterwards).

added 123 characters in body
Source Link
Tunaki
  • 9.3k
  • 1
  • 30
  • 46

The presented way is not a functional solution. It uses streams but it relies on forEach, which is the imperative way of using a Stream.

To make it better, we need to think about what we really want to do. We want to build all the permutations of the characters in a String. That means we need to have a method permutations(String) that will return all the permutations. Using Java 8, we can return a Stream<String> which will corresponds to the Stream of all the permutations.

To build those permutations, we can have a recursive algorithm:

  • If the String is empty, there are no characters, so the only result is a Stream that contains the empty String. This is the base case.
  • If the String is non-empty:
  • we remove the first character, build all the permutations without it and then prepend the first character to all the results.
  • then we remove the second character, build all the permutations without it and then prepend the second character to all the results.
  • etc. until we hit the last character.

Using Java 8, this is an implementation:

public static Stream<String> permutations(String str) {
    if (str.isEmpty()) {
        return Stream.of("");
    }
    return IntStream.range(0, str.length())
                .boxed()
                .flatMap(i ->
                  permutations(str.substring(0, i) + str.substring(i+1)).map(t -> str.charAt(i) + t)
                );
}

The base-case is handled by the if: when the String is empty, we return Stream.of(""): a Stream that contains only the empty String/

The main part is after: we create an IntStream over the indexes of the String. (Since there are unfortunately no flatMapToObj operation, we need to box each int into an Integer.) Then that's where the magic happens: for each index, we recurse by building all the permutations again, leaving the index i, and each of the result is mapped to prepend the character at index i. Since this recursive call returns a Stream<String>, this result is flat mapped (with flatMap) to have a single Stream.

With this utility method, your code is then just

permutations("ferrao").forEach(System.out::println);

That brings also a big advantage: the method is returning a Stream<String>, that is to say, the method does not actually perform the calculation. It is then up-to the caller to decide when to do it and if they want it to happen in parallel or not.

For example, to have it performed in parallel, you just need to do

permutations("ferrao").parallel().forEach(System.out::println);

The presented way is not a functional solution. It uses streams but it relies on forEach, which is the imperative way of using a Stream.

To make it better, we need to think about what we really want to do. We want to build all the permutations of the characters in a String. That means we need to have a method permutations(String) that will return all the permutations. Using Java 8, we can return a Stream<String> which will corresponds to the Stream of all the permutations.

To build those permutations, we can have a recursive algorithm:

  • If the String is empty, there are no characters, so the only result is a Stream that contains the empty String. This is the base case.
  • If the String is non-empty:
  • we remove the first character, build all the permutations without it and then prepend the first character to all the results.
  • then we remove the second character, build all the permutations without it and then prepend the second character to all the results.
  • etc. until we hit the last character.

Using Java 8, this is an implementation:

public static Stream<String> permutations(String str) {
    if (str.isEmpty()) {
        return Stream.of("");
    }
    return IntStream.range(0, str.length())
                .boxed()
                .flatMap(i ->
                  permutations(str.substring(0, i) + str.substring(i+1)).map(t -> str.charAt(i) + t)
                );
}

The base-case is handled by the if: when the String is empty, we return Stream.of(""): a Stream that contains only the empty String/

The main part is after: we create an IntStream over the indexes of the String. (Since there are unfortunately no flatMapToObj operation, we need to box each int into an Integer.) Then that's where the magic happens: for each index, we recurse by building all the permutations again, leaving the index i, and each of the result is mapped to prepend the character at index i.

With this utility method, your code is then just

permutations("ferrao").forEach(System.out::println);

That brings also a big advantage: the method is returning a Stream<String>, that is to say, the method does not actually perform the calculation. It is then up-to the caller to decide when to do it and if they want it to happen in parallel or not.

For example, to have it performed in parallel, you just need to do

permutations("ferrao").parallel().forEach(System.out::println);

The presented way is not a functional solution. It uses streams but it relies on forEach, which is the imperative way of using a Stream.

To make it better, we need to think about what we really want to do. We want to build all the permutations of the characters in a String. That means we need to have a method permutations(String) that will return all the permutations. Using Java 8, we can return a Stream<String> which will corresponds to the Stream of all the permutations.

To build those permutations, we can have a recursive algorithm:

  • If the String is empty, there are no characters, so the only result is a Stream that contains the empty String. This is the base case.
  • If the String is non-empty:
  • we remove the first character, build all the permutations without it and then prepend the first character to all the results.
  • then we remove the second character, build all the permutations without it and then prepend the second character to all the results.
  • etc. until we hit the last character.

Using Java 8, this is an implementation:

public static Stream<String> permutations(String str) {
    if (str.isEmpty()) {
        return Stream.of("");
    }
    return IntStream.range(0, str.length())
                .boxed()
                .flatMap(i ->
                  permutations(str.substring(0, i) + str.substring(i+1)).map(t -> str.charAt(i) + t)
                );
}

The base-case is handled by the if: when the String is empty, we return Stream.of(""): a Stream that contains only the empty String/

The main part is after: we create an IntStream over the indexes of the String. (Since there are unfortunately no flatMapToObj operation, we need to box each int into an Integer.) Then that's where the magic happens: for each index, we recurse by building all the permutations again, leaving the index i, and each of the result is mapped to prepend the character at index i. Since this recursive call returns a Stream<String>, this result is flat mapped (with flatMap) to have a single Stream.

With this utility method, your code is then just

permutations("ferrao").forEach(System.out::println);

That brings also a big advantage: the method is returning a Stream<String>, that is to say, the method does not actually perform the calculation. It is then up-to the caller to decide when to do it and if they want it to happen in parallel or not.

For example, to have it performed in parallel, you just need to do

permutations("ferrao").parallel().forEach(System.out::println);
Source Link
Tunaki
  • 9.3k
  • 1
  • 30
  • 46

The presented way is not a functional solution. It uses streams but it relies on forEach, which is the imperative way of using a Stream.

To make it better, we need to think about what we really want to do. We want to build all the permutations of the characters in a String. That means we need to have a method permutations(String) that will return all the permutations. Using Java 8, we can return a Stream<String> which will corresponds to the Stream of all the permutations.

To build those permutations, we can have a recursive algorithm:

  • If the String is empty, there are no characters, so the only result is a Stream that contains the empty String. This is the base case.
  • If the String is non-empty:
  • we remove the first character, build all the permutations without it and then prepend the first character to all the results.
  • then we remove the second character, build all the permutations without it and then prepend the second character to all the results.
  • etc. until we hit the last character.

Using Java 8, this is an implementation:

public static Stream<String> permutations(String str) {
    if (str.isEmpty()) {
        return Stream.of("");
    }
    return IntStream.range(0, str.length())
                .boxed()
                .flatMap(i ->
                  permutations(str.substring(0, i) + str.substring(i+1)).map(t -> str.charAt(i) + t)
                );
}

The base-case is handled by the if: when the String is empty, we return Stream.of(""): a Stream that contains only the empty String/

The main part is after: we create an IntStream over the indexes of the String. (Since there are unfortunately no flatMapToObj operation, we need to box each int into an Integer.) Then that's where the magic happens: for each index, we recurse by building all the permutations again, leaving the index i, and each of the result is mapped to prepend the character at index i.

With this utility method, your code is then just

permutations("ferrao").forEach(System.out::println);

That brings also a big advantage: the method is returning a Stream<String>, that is to say, the method does not actually perform the calculation. It is then up-to the caller to decide when to do it and if they want it to happen in parallel or not.

For example, to have it performed in parallel, you just need to do

permutations("ferrao").parallel().forEach(System.out::println);