Ilya
Ilya

Reputation: 71

Java streams collect list of objects to buckets

I have a problem of collecting some list values to buckets. For example, let's assume I have a list of Strings:

List<String> strs = Arrays.asList("ABC", "abc", "bca", "BCa", "AbC");

And I want to put the strings into set (or list) of sets, that contain only case-different strings, i.e. for example above it would be collection of two sets: [["ABC", "abc", "AbC"], ["bca", "BCa"]]

So help me please to write collector for this problem.

List<Set<String>> result = strs.stream()
                .collect(/* some collectors magic here */)

Upvotes: 5

Views: 6055

Answers (3)

user_3380739
user_3380739

Reputation: 1284

Here is code by abacus-common

List<String> strs = N.asList("ABC", "abc", "bca", "BCa", "AbC");
List<Set<String>> lists = Stream.of(strs).groupBy(N::toLowerCase, Collectors.toSet()).map(Entry::getValue).toList();

Declaration: I'm the developer of abacus-common.

Upvotes: 0

Alexis C.
Alexis C.

Reputation: 93892

The "some collectors magic" you are looking for can be done in two steps:

  • first, you need to group the elements by the property you are looking for. In this case since you want to ignore the casing, String#toLowerCase does the job (don't forget the overloaded method that takes a Locale as parameter). You also want the values grouped to be unique so you can use the overloaded version of groupingBy to put them into a Set (the default implementation uses a List)
  • since you're not interested in the keys, just grab the values from the resulting map and put them in a list (if you really need a list) using the collectingAndThen collector.

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toSet;

...

List<Set<String>> result = 
    strs.stream()
        .collect(collectingAndThen(groupingBy(String::toLowerCase, toSet()), 
                                   m -> new ArrayList<>(m.values())));

Upvotes: 11

Jean Logeart
Jean Logeart

Reputation: 53859

Try:

List<Set<String>> result = 
  strs.stream()
      .collect(groupingBy(String::toLowerCase, toSet())) // Map<String, Set<String>>
      .values()            // Collection<Set<String>>
      .stream()            // Stream<Set<String>> 
      .collect(toList());  // List<Set<String>>

Upvotes: 2

Related Questions