在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