views:

359

answers:

4

In Python, the defaultdict class provides a convenient way to create a mapping from key -> [list of values], in the following example,

from collections import defaultdict
d = defaultdict(list)
d[1].append(2)
d[1].append(3)
# d is now {1: [2, 3]}

Is there an equivalent to this in Java?

Why I chose Tendayi Mawushe's solution

This solution is good because it more faithfully renders the idea of defaultdict. However, you're not quite recovering the Pythonic expressiveness -- defaultdict is actually taking a function, not a class (below). On the other hand, that would probably make the Java code using it more verbose

> python
>>> def f(): return x
>>> x = 3
>>> from collections import defaultdict
>>> y = defaultdict(f)
>>> y[2]
3

Sorry for the latency accepting this, and thanks to Luno and dfa for their helpful answers as well.

postscript -- if only Scala compiled faster, I would use it instead...

+4  A: 

You can use multimap from apache-collections

Luno
Link: http://commons.apache.org/collections/api/org/apache/commons/collections/MultiMap.html
Mark Byers
+5  A: 

in addition to apache collections, check also google collections:

A collection similar to a Map, but which may associate multiple values with a single key. If you call put(K, V) twice, with the same key but different values, the multimap contains mappings from the key to both values.

dfa
A: 

Using just the Java runtime library you could use a HashMap and add an ArrayList to hold your values when the key does not exist yet or add the value to the list when the key does exist.

rsp
+6  A: 

There is nothing that gives the behaviour of default dict out of the box. However creating your own default dict in Java would not be that difficult.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class DefaultDict<K, V> extends HashMap<K, V> {

    Class<V> klass;
    public DefaultDict(Class klass) {
        this.klass = klass;    
    }

    @Override
    public V get(Object key) {
        V returnValue = super.get(key);
        if (returnValue == null) {
            try {
                returnValue = klass.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            this.put((K) key, returnValue);
        }
        return returnValue;
    }    
}

This class could be used like below:

public static void main(String[] args) {
    DefaultDict<Integer, List<Integer>> dict =
        new DefaultDict<Integer, List<Integer>>(ArrayList.class);
    dict.get(1).add(2);
    dict.get(1).add(3);
    System.out.println(dict);
}

This code would print: {1=[2, 3]}

Tendayi Mawushe