Erwin Dupont
Erwin Dupont

Reputation: 577

How to create nested groups using Eclipse Collection's Multimap?

I have read Map vs. Multimap with great interest. Multimaps are indeed a commonly used concept for which there's no standard JDK type.

As I am still exploring the Eclipse Collections library, I do have some questions about the usage of Eclipse Collection's Multimaps.

First, what is the most elegant way to create nested groups using Eclipse Collections? Using standard Java Streams, it is merely using another groupingBy Collector as downstream. This allows you to create nested groups as deep as you'd like.

Map<K1, Map<K2, List<V>>> collect = List.of(V, V, V, ...).stream()
    .collect(
        Collectors.groupingBy(
            Function<V, K1>,
            Collectors.groupingBy(
                Function<V, K2>,
                Collectors.toList()
            )
        )
    );

Can you achieve something similar using Eclipse Collections?


As a follow-up question, I could not find a collect method to operate on a complete group, something like:

Multimap.collectMultiValues(Function<? super RichIterable<V>,?> function)

As I am relatively new to this API, this will probably exist but in another form. Until I learn of a more elegant solution, I rely on the following methods:

  1. Multimap.keyMultiValuePairsView()
  2. Multimap.forEachKeyMultiValues(Procedure2<? super K,? super RichIterable<V>> procedure)

Upvotes: 2

Views: 341

Answers (1)

Donald Raab
Donald Raab

Reputation: 6706

Eclipse Collections works with Java Streams. There is a Collectors2 utility class in the library which returns specific types from the library like Multimap. The following code will group a List of fruit Strings by the first letter and then by the length of the fruit. There are Collectors for mutable and immutable types, so I am showing both below.

List<String> fruit = 
        List.of("apple", "apricot", "banana", "blueberry", "clementine");

Map<String, MutableListMultimap<Integer, String>> groupedMutable =
        fruit.stream().collect(
                Collectors.groupingBy(
                        each -> each.substring(0, 1),
                        Collectors2.toListMultimap(String::length)));

Map<Object, ImmutableListMultimap<Integer, String>> groupedImmutable =
        fruit.stream().collect(
                Collectors.groupingBy(
                        each -> each.substring(0, 1),
                        Collectors2.toImmutableListMultimap(String::length)));

Assertions.assertEquals(groupedImmutable, groupedImmutable);
Assertions.assertEquals(List.of("apple"), groupedMutable.get("a").get(5));
Assertions.assertEquals(List.of("apricot"), groupedMutable.get("a").get(7));
Assertions.assertEquals(List.of(), groupedMutable.get("a").get(10));
Assertions.assertEquals(List.of("banana"), groupedMutable.get("b").get(6));
Assertions.assertEquals(List.of(), groupedMutable.get("b").get(8));
Assertions.assertEquals(List.of("blueberry"), groupedMutable.get("b").get(9));
Assertions.assertEquals(List.of("clementine"), groupedMutable.get("c").get(10));
Assertions.assertEquals(List.of(), groupedMutable.get("c").get(5));

There are no Eclipse Collections specific methods for multi-level grouping. We thought Java Streams handled this fairly well, and it was better to provide interop than an alternative.

For the second part of your question (which could be a question on its own), I think the method you might be looking for is collectKeyMultiValues. I would need to see a code example to confirm if it is suitable for the problem you are trying to solve.

Upvotes: 3

Related Questions