Samrat Chakraborty
Samrat Chakraborty

Reputation: 33

Create a char count array for a String using java8 features

I wish to create a int[] of count for a particular String (comprising of only lowercase English Alphabets) using Java 8 stream API. Where arr[i] denotes the count of i-th character of English dictionary (e.g. arr[0] = count of 'a' in String str while arr[2] = count of 'c' in String str. This can be simply done by:

int[] arr = new int[26];
for(char c : str.toCharArray())
       arr[c-'a']++;

Or using IntSream in the 2nd way:

int[] arr = IntStream.range('a','z'+1).map(i -> (int)str.chars().filter(c -> c == i).count()).toArray();

But the problem with the second approach is that the String is traversed 26 times for each of the characters from 'a' to 'z'

Can you suggest a better way of achieving the same using java8-stream API?

PS: I know this can be done using Map but I need int[]

Upvotes: 3

Views: 475

Answers (2)

Andrew
Andrew

Reputation: 49656

int[] r = str.chars()
             .boxed()
             .reduce(new int[26], 
                     (a, c) -> { ++a[c - 'a']; return a; }, 
                     (a1, a2) -> a1);

You know the former is simpler and better. My answer just proves it's feasible with the Stream API, and doesn't suggest that you should go with it. Personally, I would choose the map approach as the most intuitive one.

As pointed out by @Holger, collect is a better option here

str.chars()
   .map(c -> c - 'a')
   .collect(() -> new int[26], 
            (a, i)-> a[i]++, 
            (a1, a2) -> /* left as an exercise to the reader*/);

Upvotes: 6

pero_hero
pero_hero

Reputation: 3204

if you want to use streams and keep the iterative approach, you could do it as well like this:

final int count[] = new int[26];
test.chars().forEach(c -> count[c-'a']++);

Upvotes: 2

Related Questions