Grzesiek Chyla
Grzesiek Chyla

Reputation: 103

Counting occurences of chars in string with stream

I'm trying to understand a data flow of streams in Java. My task is to put occurrences of each letter in list of strings

List<String> words = Arrays.asList("Welcome", "to", "the", "java", "world");

into

Map<String, Long>

using a one-liner stream.

I know, that in the first place we can stream each word from the list, then I need to separate it into chars, then put each char as key and count its occurrence as value and in the end return the whole map.

It is so complicated to understand. Could someone explain to me how to do it?

Upvotes: 3

Views: 26868

Answers (5)

vplust
vplust

Reputation: 1

This looks simpler to me.

Map<String, Long> charCount = words.stream().map(s -> s.split("")).flatMap(Arrays::stream)
                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

{a=2, c=1, d=1, e=3, h=1, j=1, l=2, m=1, o=3, r=1, t=2, v=1, w=1, W=1}

Upvotes: 0

Ankur Yadav
Ankur Yadav

Reputation: 271

In Kotlin:

val str = "Occurrences"
val results: Map<String, Long> =
        stream(str.split("").toTypedArray()).map{n-> n.lowercase()}
            .collect(
                Collectors.groupingBy({ it  },
                    { LinkedHashMap() },
                    Collectors.counting()
                )
            )

Log.w("occurrencesResult",results.toString())

Upvotes: 0

Denys Shelupets
Denys Shelupets

Reputation: 21

More readable using flatMapToInt than flatMap(a -> a.chars().mapToObj(c -> (char) c))

words.stream()
            .flatMapToInt(String::chars) //IntStream
            .mapToObj(c -> (char) c)     //Stream<Character>
            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

Upvotes: 2

Naman
Naman

Reputation: 31878

It could be done as Willis pointed out using the flatMap and groupingBy collector. But, the expected output type should be Map<Character, Long> fo that as in:

Map<Character, Long> charFrequency = words.stream() //Stream<String>
        .flatMap(a -> a.chars().mapToObj(c -> (char) c)) // Stream<Character>
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

Upvotes: 10

Willis Blackburn
Willis Blackburn

Reputation: 8204

The thing you need to know is that flatMap is the function that you can use to convert the strings into individual characters. While regular map function just converts each stream element into a different element, flatMap converts each element into a stream of elements, then concatenates those streams together.

The function that converts a String into a stream of characters is String.chars.

When you want to build a new collection from a stream, you usually use a collector. Using the function Collectors.groupingBy you can produce a collector that will create a Map, given two functions, one to produce the key for each stream value, and the other to produce the value. There's a variant of this that will let you pass another collector in as the second parameter instead of a function; try Collectors.counting.

Upvotes: 2

Related Questions