scriptfoo
scriptfoo

Reputation: 513

Java: a sorted multimap which is a map of lists and not a map of sets

I am looking for a sorted multimap, where a single key can be mapped to multiple values, no matter what is returned by equals() of these values. Thus, it should not be something like this:

import com.google.common.collect.*;

public class Test {
    public static void main(String[] args) {
        Multimap<Double, String> multimap = TreeMultimap.create();
        multimap.put(3.0, "a");
        multimap.put(3.0, "a");
        multimap.put(2.0, "b");
        // prints "b", "a"
        for(String s : multimap.values())
            System.out.println(s);
    }
}

I have always been using java.util.Map<Key, List<Value>> but it comes with a bit of boilerplate.

One of the possibilities is a parameterised type:

public class SortedMapOfLists<K, V> {
    SortedMap<K, List<V>> map = new TreeMap<>();
    public void put(K key, V value) {
        List<V> list = map.get(key);
        if(list == null) {
            list = new ArrayList<>();
            map.put(key, list);
        }
        list.add(value);
    }
    public List<V> values() {
        List<V> values = new ArrayList<>();
        for(List<V> list : map.values())
            for(V value : list)
                values.add(value);
        return values;
    }
}

but this implementation has a limited functionality.

Upvotes: 0

Views: 206

Answers (2)

Neil Coffey
Neil Coffey

Reputation: 21795

I wonder why rushing to a third party library is the first port of call here. It seems to me that you can achieve what you require with the standard collections framework without as much boilerplate as you suggest. For example, given a plain old TreeMap:

SortedMap<String, List<String>> map = new TreeMap<>();

your put method can be replaced with a single line:

map.computeIfAbsent(key, k -> new ArrayList<>()).add(val);

Similarly, if you want to get the values associated with a given key and return a shallow copy of the list (or empty if there are no values associated-- which your method doesn't actually cover but maybe you'd want), you can do:

List<String> vals = new ArrayList<>(map.getOrDefault(key, Collections.emptyList()));

From the specific use case you mention, a third party library seems to be an unnecessary dependency for very little benefit.

Upvotes: 2

Louis Wasserman
Louis Wasserman

Reputation: 198163

It sounds like you're looking for MultimapBuilder.treeKeys().arrayListValues().build().

Upvotes: 5

Related Questions