Jay Singh
Jay Singh

Reputation: 13

Letter Case Permutation using java streams

How do I use Java streams to find all differences in letter casing based on a given string input?

To solidify my understanding of Java Streams. I am solving leetcode easy questions using java streams. I am confused on how to solve this backtracking problem using streams. I am especially confused how to map a character twice ie lower case and upper case.

Input: S = "a1b2"
Output: ["a1b2","a1B2","A1b2","A1B2"]

Stream.of(S.split(""))
      .map(str -> str.toUpperCase()) // this will upper case only
      .map(str -> str.toLowerCase()) // this will lower case only. how to use both?
      .collect(Collectors.toList()); //how do i concatenate strings before adding into list 

Apologies in advance for bad english

Upvotes: 1

Views: 202

Answers (2)

As rzwitserloot says, this kind of problems normally are not attacked using streams, however I will try to solve the doubts you have in the question:

For a stream that has the uppercase and lowercase version of the letter you can use something like this:

Stream.of(input.split(""))
    .filter(c -> Character.isLetter(c.charAt(0))) // Filter only letters
    .flatMap(str -> Stream.of(str, str.toUpperCase())) // Flatten the stream with both letters
    .collect(Collectors.toList())

If you want to concatenate Strings that you have in a list after mapping the values in the stream, instead of using Collectors.toList() you can use Collectors.joining() like this:

Stream.of(input.split(""))
    .filter(c -> Character.isLetter(c.charAt(0))) // Filter only letters
    .flatMap(str -> Stream.of(str, str.toUpperCase()))
    .collect(Collectors.joining()) // this collector can receive a delimiter if you want to join them separated by comman for example.

Now for the problem in question, you don't need to have the upper and lower case version of the letters, just to filter the letters from the input word and the start replacing them in the word on by one for the uppercase version, this can be a possible solution:

    public static void main(String[] args) {
        String input = "a1b2";
        // Output: ["a1b2","a1B2","A1b2","A1B2"];

        Set<String> result = new HashSet<>();
        result.add(input);
        Stream.of(input.split(""))
                .filter(c -> Character.isLetter(c.charAt(0)))
                .forEach(c -> result.addAll(
                        result.stream().map(str -> {
                            if (!str.equals(input.toUpperCase())) {
                                return str.replaceFirst(c, c.toUpperCase());
                            }
                            return str;
                        }).collect(Collectors.toSet()))
                );
        System.out.println(result);
    }

Upvotes: 1

rzwitserloot
rzwitserloot

Reputation: 103073

You can do that with flatmap, but your output would be ["a", "A", "1", "b", "B", "2"] which is nothing like what you want. Note that your output gets larger quickly; the # of outputs doubles for every letter in the input. That doesn't match up well with what streams even do.

In general what you want to do here is impossible or requires such bending of the tool that it's akin to trying to smear butter on your sandwich with a hammer. You probably can, but why in the blazes do you want to? This is not going to improve your skills at using that hammer.

Upvotes: 1

Related Questions