Home > OS >  Count/sort all letters in a string with a stream in Java (ignoring numbers)
Count/sort all letters in a string with a stream in Java (ignoring numbers)

Time:08-14

My friend says this is not possible, but I believe she is wrong. Assume I have a list of strings made of alphanumeric characters:

"aa1, aaaa, aaa, a12, a5, 44a44, 3232aa"

I want to write a stream that will:

  • look at each individual element
  • identify count all of the letters (ignoring numbers)
  • if the number is odd, do x
  • if the number is even, do y

She says that this will result in terminal operations within the stream (count) and it's not possible. I looked online and, after starting, my thought was it would be easier to just filter out all the even ones. I ended up with this:

List<String> evaluateStrings = validChars.stream().filter(x -> x.replaceAll("\\d","").length() %2 == 0).collect(Collectors.toList());

But this doesn't even filter out all the numbers.

Any thoughts on this?

CodePudding user response:

Try using the map function to remove the numbers.

I would highly recommend filtering before the map to check for null strings, otherwise you might somehow get a null pointer exception (NPE). I highly stress filtering out null values when using streams and transforming data, it will save you lots of trouble in the future as you start streaming different data types from different sources.

List<String> evaluateStrings = validChars.stream()
// transform the data in the stream, remove numeric chars
.map(x -> x.replaceAll("\\d",""))
// Filter to allow even length strings
.filter(x -> x.length() %2 == 0)
// Collect the transformed and filtered results.
.collect(Collectors.toList());

If you want to collect all your strings into a collection, while both doing x and why depending on even or oddness:

List<String> evaluateStrings = validChars.stream()
// transform the data in the stream, remove numeric chars
.map(x -> x.replaceAll("\\d","")
// Filter to allow even length strings
.map(x -> {
      if(x.length() %2 == 0) {
        //if number is even, do x
        return doY(x);
      } else {
        // If number is odd, do y
        return doX(x);
      }
})
// Collect the transformed and filtered results.
.collect(Collectors.toList());

CodePudding user response:

Yes, possible

My friend says this is not possible, but I believe she is wrong

Yes, she is wrong. You can accomplish all that in a single line of code using streams.

Code points

Avoid the char/Character type in Java, as it has been essentially broken since Java 2, and legacy since Java 5. As a 16-bit value, char is physically incapable of representing most characters.

Your Question is not clear. I am guessing that the result of “do x” and “do y” is a string that you want to collect.

Below is some example code.

Stream#map

We use Stream#map to transform each word of the input into a count of its letters after filtering out code points representing digits or other non-alphabetic characters.

We use a ternary operator to call either the method for even numbers or the method for odd numbers. Both methods return a String object. We collect those returned String objects in a list.

List < String > results = 
    Arrays
    .stream(
        "aa1, aaaa, aaa, a12, a5, 44a44, 3232aa"
        .split( ", " )
    )
    .map(
        string -> 
            string
            .codePoints()  // Returns an `IntStream`
            .filter( Character :: isAlphabetic ) // Eliminate digits, punctuation, etc.
            .count()      // Count how many alphabetic characters found in that word.
            % 2 == 0      // Use modulo to test for even number.
            ?             // Ternary operator. 
                doEven()  // returns a `String` object.
            : 
                doOdd()   // returns a `String` object.
    )
    .toList()
;

See this code run live at Ideone.com.

[even, even, odd, odd, odd, odd, even]

  • Related