有没有Java相当于Python的defaultdict?

gat*_*ado 40 python java hashmap

在Python中,defaultdict该类提供了一种方便的方法来创建映射key -> [list of values],在以下示例中,

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

在Java中是否有相同的功能?

Ten*_*she 25

没有什么可以使默认dict的行为开箱即用.但是,在Java中创建自己的默认dict并不困难.

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;
    }    
}
Run Code Online (Sandbox Code Playgroud)

这个类可以像下面这样使用:

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);
}
Run Code Online (Sandbox Code Playgroud)

此代码将打印: {1=[2, 3]}

  • 您也可以尝试传递Guava"供应商",而不是使用"Class" - 请参阅http://docs.guava-libraries.googlecode.com/git-history/v10.0/javadoc/com/google/common /base/Supplier.html (5认同)
  • 或者,如果您不希望使用番石榴,只需在DefaultDict中定义自己的Supplier &lt;V&gt;接口。 (3认同)

dim*_*414 11

在你想要的大多数常见情况下defaultdict,你会对设计合理的Multimap或Multiset更加满意,这正是你真正想要的.Multimap是一个键 - >集合映射(默认是一个空集合),Multiset是一个键 - > int映射(默认为零).

Guava提供了Multimaps和Multisets的非常好的实现,几乎涵盖了所有用例.

但是(这就是为什么我发布了一个新答案)使用Java 8,您现在可以复制剩余的defaultdict任何现有用例Map.

  • getOrDefault()顾名思义,如果存在,则返回值,或返回默认值.这不会在地图中存储默认值.
  • computeIfAbsent()计算从所提供的功能(这可能总是返回相同的默认值)和值不会返回之前存储在地图中的计算值.

如果要封装这些调用,可以使用Guava ForwardingMap:

public class DefaultMap<K, V> extends ForwardingMap<K, V> {
  private final Map<K, V> delegate;
  private final Supplier<V> defaultSupplier;

  /**
   * Creates a map which uses the given value as the default for <i>all</i>
   * keys. You should only use immutable values as a shared default key.
   * Prefer {@link #create(Supplier)} to construct a new instance for each key.
   */
  public static DefaultMap<K, V> create(V defaultValue) {
    return create(() -> defaultValue);
  }

  public static DefaultMap<K, V> create(Supplier<V> defaultSupplier) {
    return new DefaultMap<>(new HashMap<>(), defaultSupplier);
  }

  public DefaultMap<K, V>(Map<K, V> delegate, Supplier<V> defaultSupplier) {
    this.delegate = Objects.requireNonNull(delegate);
    this.defaultSupplier = Objects.requireNonNull(defaultSupplier);
  }

  @Override
  public V get(K key) {
    return delegate().computeIfAbsent(key, k -> defaultSupplier.get());
  }
}
Run Code Online (Sandbox Code Playgroud)

然后构造您的默认地图,如下所示:

Map<String, List<String>> defaultMap = DefaultMap.create(ArrayList::new);
Run Code Online (Sandbox Code Playgroud)


dfa*_*dfa 8

除了apache集合,还要检查google集合:

类似于Map的集合,但可以将多个值与单个键相关联.如果使用相同的键但不同的值调用put(K,V)两次,则multimap包含从键到两个值的映射.


gar*_*may 8

在 Java 8+ 中,您可以使用:

map.computeIfAbsent(1, k -> new ArrayList<Integer>()).add(2);
Run Code Online (Sandbox Code Playgroud)