是否有与Python的defaultdict相当的Java?

2024-04-26 18:24:29 发布

您现在位置:Python中文网/ 问答频道 /正文

在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]}

在Java中是否有与此等价的东西?


Tags: of方法keyfromimport示例isjava
3条回答

除了apache集合之外,还要检查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.

没有什么能让默认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;
    }    
}

这个类可以如下使用:

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);
}

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

在大多数需要defaultdict的情况下,使用设计正确的Multimap或Multiset会让您更加高兴,这正是您真正需要的。多重映射是键->;集合映射(默认为空集合),多重集是键->;整数映射(默认为零)。

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

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

  • ^{},顾名思义,返回值(如果存在),或者返回默认值。此不会在映射中存储默认值。
  • ^{}从提供的函数中计算一个值(该函数始终可以返回相同的默认值),并且在返回之前将计算值存储在映射中。

如果要封装这些调用,可以使用番石榴的^{}

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());
  }
}

然后像这样构造默认映射:

Map<String, List<String>> defaultMap = DefaultMap.create(ArrayList::new);

相关问题 更多 >