1

I tried to convert data from the list of strings into a Map<String, Integer> with the Stream API.

But the way I did it is not correct:

public static Map<String, Integer> converter (List<String> data){
        return data.stream().collect(Collectors.toMap(e->e, Function.identity()));

If we have List.of("5", "7", "5", "8", "9", "8")

task №1 as key - String, and value - character frequency

task №2 as key - String, and value - string converted to integer

3
  • What do you want as your key and value? Your current stream would return Map<String,String>. Note that e->e and Function.identity() do the same thing. Commented Mar 31, 2022 at 17:07
  • If we have List.of("5", "7", ''5", "8", "9,"8") , as key - String, and about value -maybe, character frequency Commented Mar 31, 2022 at 17:17
  • "String, and value- converted string to integer" You realize you lose data doing this right since the key is unique and will overwrite whatever was previously there. You would only have one 5 = 5 value in your map, not two. Commented Mar 31, 2022 at 17:26

2 Answers 2

2

Try it like this for a frequency. Note that a map can't have duplicate keys.

List<String> list2 = List.of("5", "7", "5", "8", "9","8");
  • the key is the String.
  • the value starts a 1.
  • the Integers::sum adds 1 for every occurrence.
Map<String, Integer> freq = list2.stream().collect(Collectors.toMap(
         e->e, (a)->1, Integer::sum));

freq.entrySet().forEach(System.out::println);

prints

5=2
7=1
8=2
9=1

for the second task, to convert the strings to ints is trivial. But remember that dups can't exist so they have to be properly merged. This is similar to the first task except instead of counting we're just converting to an integer. Since you have duplicate integers, you need to provide instructions on what to do. That is the merge function (a,b)->a which says for existing value a and new value b, just keep a

List<String> list2 = List.of("5", "7", "5", "8", "9","8");
Map<String, Integer> map = list2.stream().collectCollectors.toMap(e->e,
              Integer::valueOf,
              (a,b)->a); // just keep the first one

prints

5=5
7=7
8=8
9=9
Sign up to request clarification or add additional context in comments.

1 Comment

You updated your question so I provide additional information to address the second part.
1

task №1 as key - String, and value - character frequency

In order to obtain the frequency of every character, you need to flatten each string in a list (i.e. split every string into characters).

Since Java 9 we can use method chars() which returns a stream of characters represented with int primitives.

flatMapToInt(String::chars) will produce an IntStream, containing characters from every string in the given list.

Then mapToObj() creates a single-character string for every stream element.

To generate the map of frequencies, we can utilize collector Collectors.groupingBy(). Function.identity() is used as the first argument is an equivalent of e -> e, it's just a way to tell that stream elements will be used as a key without any changes. The second argument is a downstream collector Collectors.counting(), that generates the number of elements mapped to a particular key.

public static Map<String, Long> getCharacterFrequency(List<String> list) {
    return list.stream()                               // Stream<String>
            .flatMapToInt(String::chars)               // IntStream
            .mapToObj(ch -> String.valueOf((char) ch)) // String<String>
            .collect(Collectors.groupingBy(Function.identity(),
                                           Collectors.counting()));
}

task №2 as key - String, and value - string converted to integer

You can do it by using a flavor of collector Collectors.toMap() that expects three arguments:

  • keyMapper - a function that produces the key from a stream element;
  • valueMapper - a function that produces the value from a stream element;
  • mergeFunction - a function that determines how to resolve a situation when two values happens to be mapped to the same key.

Although, the mergeFunction in the code below is not doing anything special, it needs to be provided, otherwise the first encountered duplicate will cause an IllegalStateException.

public static Map<String, Integer> getStringValuesMappedToInts(List<String> list) {
    return list.stream()
            .collect(Collectors.toMap(Function.identity(), // key (String)
                                      Integer::valueOf,   // value (Integer)
                                      (v1, v2) -> v1));    // function that resolves collisions
}

main() - demo

public static void main(String[] args) {
    List<String> source = List.of("5", "7", "57", "59", "5", "8", "99", "9", "8");
    // task 1
    System.out.println("task 1:\n" + getCharacterFrequency(source));
    // task 2
    System.out.println("task 2:\n" + getStringValuesMappedToInts(source));
}

Output

task 1:
{5=4, 7=2, 8=2, 9=4}
task 2:
{99=99, 57=57, 59=59, 5=5, 7=7, 8=8, 9=9}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.