在Python中,defaultdict
类提供了一个便捷的方式从key -> [list of values]
创建一个映射,在下面的例子中,是否有Python的defaultdict的Java等价物?
from collections import defaultdict
d = defaultdict(list)
d[1].append(2)
d[1].append(3)
# d is now {1: [2, 3]}
是否有一个相当于这个在Java中?
在Python中,defaultdict
类提供了一个便捷的方式从key -> [list of values]
创建一个映射,在下面的例子中,是否有Python的defaultdict的Java等价物?
from collections import defaultdict
d = defaultdict(list)
d[1].append(2)
d[1].append(3)
# d is now {1: [2, 3]}
是否有一个相当于这个在Java中?
没有任何东西给出默认代码的行为。然而,在Java中创建自己的默认字典并不会那么困难。
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]}
您可以从Apache Commons使用MultiMap
。
链接:http://commons.apache.org/collections/api/org/apache/commons/collections/MultiMap.html – 2009-11-23 21:46:45
链接中断 – HuStmpHrrr 2015-05-11 13:27:47
,也google collections检查:
类似的地图收藏,但它可以将多个值与一个键关联。如果使用相同的键但不同的值调用put(K,V)两次,则multimap包含键与两个值的映射。
只需使用Java运行时库,你可以使用一个HashMap
并添加ArrayList
握住你的值时,关键不存在或值添加到列表中时,关键是存在的。
从@ tendayi-mawushe的解决方案并没有为我与基本类型的工作(如InstantiationException Integer
),这里有一个与Integer,Double,Float一起使用的实现。我经常使用这些地图,并添加静态构造函数conveninence
import java.util.HashMap;
import java.util.Map;
/** Simulate the behaviour of Python's defaultdict */
public class DefaultHashMap<K, V> extends HashMap<K, V> {
private static final long serialVersionUID = 1L;
private final Class<V> cls;
private final Number defaultValue;
@SuppressWarnings({ "rawtypes", "unchecked" })
public DefaultHashMap(Class factory) {
this.cls = factory;
this.defaultValue = null;
}
public DefaultHashMap(Number defaultValue) {
this.cls = null;
this.defaultValue = defaultValue;
}
@SuppressWarnings("unchecked")
@Override
public V get(Object key) {
V value = super.get(key);
if (value == null) {
if (defaultValue == null) {
try {
value = cls.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
} else {
value = (V) defaultValue;
}
this.put((K) key, value);
}
return value;
}
public static <T> Map<T, Integer> intDefaultMap() {
return new DefaultHashMap<T, Integer>(0);
}
public static <T> Map<T, Double> doubleDefaultMap() {
return new DefaultHashMap<T, Double>(0d);
}
public static <T> Map<T, Float> floatDefaultMap() {
return new DefaultHashMap<T, Float>(0f);
}
public static <T> Map<T, String> stringDefaultMap() {
return new DefaultHashMap<T, String>(String.class);
}
}
和测试,为礼貌:
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.junit.Test;
public class DefaultHashMapTest {
@Test
public void test() {
Map<String, List<String>> dm = new DefaultHashMap<String, List<String>>(
ArrayList.class);
dm.get("nokey").add("one");
dm.get("nokey").add("two");
assertEquals(2, dm.get("nokey").size());
assertEquals(0, dm.get("nokey2").size());
}
@Test
public void testInt() {
Map<String, Integer> dm = DefaultHashMap.intDefaultMap();
assertEquals(new Integer(0), dm.get("nokey"));
assertEquals(new Integer(0), dm.get("nokey2"));
dm.put("nokey", 3);
assertEquals(new Integer(0), dm.get("nokey2"));
dm.put("nokey3", 3);
assertEquals(new Integer(3), dm.get("nokey3"));
}
@Test
public void testString() {
Map<String, String> dm = DefaultHashMap.stringDefaultMap();
assertEquals("", dm.get("nokey"));
dm.put("nokey1", "mykey");
assertEquals("mykey", dm.get("nokey1"));
}
}
在最常见的情况下,你想有一个defaultdict
,你会更快乐用适当设计的Multimap或Multiset,这是你真正想要的。 Multimap是一个关键 - >集合映射(默认为空集合),Multiset是关键 - > int映射(默认为零)。
Guava提供了非常好的实现这将涵盖几乎所有的用例。
但是(这就是为什么我发布了一个新答案)与Java 8现在可以复制defaultdict
的剩余用例与任何现有Map
。
getOrDefault()
,顾名思义,返回值,如果存在,或返回一个默认值。这不存储在地图中的默认值。computeIfAbsent()
通过提供的函数计算出一个值(它总是可以返回相同的默认值)并且确实将存储在地图中,然后返回。如果你想封装这些调用,您可以使用番石榴的ForwardingMap
:
public class DefaultMap<K, V> extends ForwardingMap<K, V> {
private final Map<K, V> delegate;
private final Supplier<V> default;
public static DefaultMap<K, V> create(V default) {
return create(() -> default);
}
public static DefaultMap<K, V> create(Supplier<V> default) {
return new DefaultMap<>(new HashMap<>(), default);
public DefaultMap<K, V>(Map<K, V> delegate, Supplier<V> default) {
this.delegate = delegate;
}
@Override
public V get(K key) {
return delegate().computeIfAbsent(key, k -> supplier.get());
}
}
然后构造像这样的默认地图:
Map<String, List<String>> defaultMap = DefaultMap.create(ArrayList::new);
任何反馈,downvoter? – dimo414 2017-06-30 06:25:19
我写的库Guavaberry包含这样的数据结构:DefaultHashMap。
它经过高度测试和记录。您可以通过Maven Central轻松找到并整合它。
主要的优点是它使用lambda来定义工厂方法。所以,你可以添加一个arbitrarly定义的类的实例(而不是依赖于默认的构造函数存在):
DefaultHashMap<Integer, List<String>> map = new DefaultHashMap(() -> new ArrayList<>());
map.get(11).add("first");
我希望能有所帮助。
如果不是从'HashMap'扩展你使用'ForwardingMap'并允许调用者指定底层映射,它会更有用。喜欢构成继承。 – dimo414 2018-03-10 01:46:59
除了使用'Class',您还可以尝试传递一个番石榴'供应商' - 请参阅http://docs.guava-libraries.googlecode.com/git-history/v10.0/javadoc/com/google/common/base/Supplier.html – 2011-10-03 01:29:01
或者,如果您不想要Guava依赖,只需在'DefaultDict'中定义你自己的'Supplier'接口。 –
Soulman
2012-11-27 13:41:09
我宁愿使用我自己的值构造'DefaultDict':public DefaultDict(V value){this.value = value; }' – 2014-06-07 01:43:22