我需要从键列表到值的映射。我知道我可以像这样写自己的代码:
Map<Person, Map<Daytime, Map<Food, Integer>>> eaten = ...;
现在我希望有一些get
和put
方法,如下所示:
Integer numberOfEggsIAteInTheMorning = eaten.get(me, morning, scrambledEggs);
eaten.put(me, evening, scrambledEggs, 1);
您是否了解具有此类API的现有类?我自己也懒得自己写。 ;)
答案 0 :(得分:2)
如果你寻找一种更通用的方法,并且你可能有超过2或3个“链式步骤”,我建议应用一些不同的结构方法,而不是坚持只使用基本的集合类。我觉得如果正确应用Composite Pattern可能是正确的选择。
编辑:由于请求的示例
完整的例子有点费时,所以让我用脏Java /伪代码混合解释我的想法(我甚至不确定我是否错过了什么!!!)。让我们考虑我们有类BaseMap:
abstract class BaseMap {
public abstract Object getValue(Object.. keys);
public abstract void putValue(Object value, Object.. keys);
}
然后我们可以将ObjectMap作为复合结构的“叶子”:
class ObjectsMap extends BaseMap {
private Map<Object, Object> map = new [...]
public Object getValue(Object.. keys) {
// assert that keys.length == 1
return map.get(keys[0]);
}
public void putValue(Object value, Object.. keys) {
// assert that keys.length = 1
map.put(keys[0], value);
}
}
实际的复合材料就是这样:
class CompositeMap extends BaseMap {
private Map<Object, BaseMap> compositeMaps = new [...]
public Object getValue(Object.. keys) {
// assert that keys.length > 1
return compositeMap.get(keys[0]).getValue(/* System.arrayCopy => subset of elements {keys_1, .. ,keys_max} */);
}
public void putValue(Object value, Object.. keys) {
// assert keys.length > 1
BaseMap newMap = null;
if (keys.length = 2) -> newMap = new ObjectsMap()
else newMap = new CompositeMap();
newMap.putValue(value, /*subset of keys {keys_1, .. , keys_max}*/);
}
}
答案 1 :(得分:1)
实现一般的链式地图很难。
班级宣言怎么样? (您不能拥有可变数量的类型参数。
class ChainedMap<K1..., V>
另一种选择是让ChainedMapUtil
类以递归方式执行put / get。
以下是递归获取的示例。 (虽然我必须说,但是很难解决。)
import java.util.*;
public class Test {
public static Object chainedGet(Map<?, ?> map, Object... keys) {
Object k = keys[0];
if (!map.containsKey(k)) return null;
if (keys.length == 1) return map.get(k);
Object[] tailKeys = Arrays.copyOfRange(keys, 1, keys.length);
return chainedGet((Map<?,?>) map.get(k), tailKeys);
}
public static void main(String[] arg) {
Map<String, String> m1 = new HashMap<String, String>();
m1.put("ipsum", "dolor");
Map<Integer, Map<String, String>> m2 =
new HashMap<Integer, Map<String, String>>();
m2.put(17, m1);
Map<String, Map<Integer, Map<String, String>>> chained =
new HashMap<String, Map<Integer, Map<String, String>>>();
chained.put("lorem", m2);
System.out.println(chainedGet(chained, "lorem", 17, "ipsum")); // dolor
System.out.println(chainedGet(chained, "lorem", 19, "ipsum")); // null
}
}
答案 2 :(得分:1)
您可以使用org.apache.commons.collections.keyvalue.MultiKey
:Map<Multikey, Object>
答案 3 :(得分:0)
如果你打算写自己的,我会建议
eaten.increment(me, evening, scrambledEggs);
您可以使用复合键
eaten.increment(Key.of(me, evening, scrambledEggs));
(TObjectIntHashMap支持增量和调整)
您甚至可能不需要自定义密钥。
eaten.increment(me + "," + evening + "," + scrambledEggs);
使用split()
分解密钥相当容易答案 4 :(得分:0)
我曾经使用3个键制作地图只是为了好玩。可能你可以使用它而不是使用链式地图:
public class ThreeKeyMap<K1,K2,K3,V>{
class wrap{
K1 k1;
K2 k2;
K3 k3;
public wrap(K1 k1,K2 k2,K3 k3) {
this.k1=k1;this.k2=k2;this.k3=k3;
}
@Override
public boolean equals(Object arg0) {
// TODO Auto-generated method stub
wrap o=(wrap)arg0;
if(!this.k1.equals(o.k1))
return false;
if(!this.k2.equals(o.k2))
return false;
if(!this.k2.equals(o.k2))
return false;
return true;
}
@Override
public int hashCode() {
int result=17;
result=37*result+k1.hashCode();
result=37*result+k2.hashCode();
result=37*result+k3.hashCode();
return result;
}
}
HashMap<wrap,V> map=new HashMap<wrap, V>();
public V put(K1 k1,K2 k2,K3 k3,V arg1) {
return map.put(new wrap(k1,k2,k3), arg1);
}
public V get(Object k1,Object k2,Object k3) {
return map.get(new wrap((K1)k1,(K2)k2,(K3)k3));
}
public static void main(String[] args) {
ThreeKeyMap<Integer,Integer,Integer,String> birthDay=new ThreeKeyMap<Integer, Integer, Integer, String>();
birthDay.put(1, 1,1986,"Emil");
birthDay.put(2,4,2009, "Ansih");
birthDay.put(1, 1,1986,"Praveen");
System.out.println(birthDay.get(1,1,1986));
}
}
<强>更新强>
正如@Arturs Licis建议的那样。我在网上查找了复合模式,我用它写了一个样本。我猜这是复合的。如果不是这样,请发表评论。
人员类:
public class Person {
private final String name;
private Map<Time, Food> map = new HashMap<Time, Food>();
public Person(String name) {
this.name = name;
}
void addTimeFood(Time time, Food food) {
map.put(time, food);
}
public String getName() {
return name;
}
Food getFood(Time time) {
Food tmp = null;
return (tmp = map.get(time)) == null ? Food.NoFood : tmp;
}
// main to test the person class
public static void main(String[] args) {
Person p1 = new Person("Jack");
p1.addTimeFood(Time.morning, Food.Bread);
p1.addTimeFood(Time.evening, Food.Chicken);
Person p2 = new Person("Jill");
p2.addTimeFood(Time.morning, Food.Egg);
p2.addTimeFood(Time.evening, Food.Rice);
Map<String, Person> map = new HashMap<String, Person>();
map.put(p1.getName(), p1);
map.put(p2.getName(), p2);
System.out.println(map.get("Jack").getFood(Time.evening));
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append(name).append("\n");
b.append(map);
return b.toString();
}
}
食品类:
public enum Food {
Rice,
Egg,
Chicken,
Bread,
NoFood;
}
时间等级:
public enum Time {
morning,
evening,
night
}