我需要的是一个Map,它将多个键映射到一个值(在我的情况下是3个键映射到1个值),这样3个键一起唯一地标识一个值。这可以通过嵌套地图轻松完成,例如:
Map<String, Map<Integer, Map<Double, Object>>> map = new HashMap<>();
Object value = map.get("foo").get(3).get(1.23);
但是,我还希望仅使用某些键就可以获取值列表,例如:
List<Object> values1 = map.get("foo"); // All values with "foo" as its String-key
List<Object> values2 = map.get(3).get(1.23); // All values with 3 as its Integer-key AND 1.23 as its Double-key
Java中是否有一个实现此类数据结构的类,如果没有,我该如何自己做呢?
答案 0 :(得分:0)
标准库中没有满足您需求的接口。我认为您已经有了正确的方法,下面是一个简单的类对其进行扩展:
import static java.util.Collections.emptyMap;
import static java.util.stream.Collectors.toList;
public class ThreeMap<K1, K2, K3, V> {
Map<K1, Map<K2, Map<K3, V>>> map = new HashMap<>();
public V get(K1 a, K2 b, K3 c) {
return map.getOrDefault(a, emptyMap()).getOrDefault(b, emptyMap()).get(c);
}
public V put(K1 a, K2 b, K3 c, V v) {
return map.computeIfAbsent(a, mapProvider()).computeIfAbsent(b, mapProvider()).put(c, v);
}
public Collection<V> getAllValues(K1 a) {
return map.getOrDefault(a, emptyMap()).entrySet().stream().flatMap(e -> e.getValue().values().stream()).collect(toList());
}
public Collection<V> getAllValues(K1 a, K2 b) {
return map.getOrDefault(a, emptyMap()).getOrDefault(b, emptyMap()).entrySet().stream().map(e -> e.getValue()).collect(toList());
}
private <K, A, B> Function<K, Map<A, B>> mapProvider() {
// for convenient use in computeIfAbsent
return k -> new HashMap<>();
}
}
答案 1 :(得分:0)
您在此处描述的内容似乎是一个经典的DB表,其中包含4列,其中3列将是关键。因此,我将继续创建具有三种不同类型的自定义密钥。
public class CompositeKey {
public String stringKey;
public Integer integerKey;
public Long longKey;
}
由您来建模不同子键的约束,例如如果所有这些都是必需的。如果您实现equals和hashCode,那么简单的Map<CompositeKey,Object>
就可以解决简单的查询。
对于其他查询类型,您将必须实现自己的存储库并决定是否向该查询添加索引,也不能。例如,如果您希望获得具有特定Integer
值且没有索引的所有值,则必须进行全面扫描(遍历地图中的所有条目)。如果要复制数据库索引的功能,则必须保留从键的子集到可能值列表的映射。在这种情况下,您将无法直接使用地图,而必须使用存储库实现来执行所有操作(put
,get
等)。
答案 2 :(得分:0)
我将创建一个新类,并将这3个键作为属性,例如
class CompositeKey {
private String key1;
private Integer key2;
private Double key3;
public CompositeKey(String key1, Integer key2, Double key3) {
this.key1 = key1;
this.key2 = key2;
this.key3 = key3;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key1 == null) ? 0 : key1.hashCode());
result = prime * result + ((key2 == null) ? 0 : key2.hashCode());
result = prime * result + ((key3 == null) ? 0 : key3.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CompositeKey other = (CompositeKey) obj;
if (key1 == null) {
if (other.key1 != null)
return false;
} else if (!key1.equals(other.key1))
return false;
if (key2 == null) {
if (other.key2 != null)
return false;
} else if (!key2.equals(other.key2))
return false;
if (key3 == null) {
if (other.key3 != null)
return false;
} else if (!key3.equals(other.key3))
return false;
return true;
}
public String getKey1() {
return key1;
}
public Integer getKey2() {
return key2;
}
public Double getKey3() {
return key3;
}
}
然后我将为每个键创建3个索引图,如下所示
// 3 index maps
// List<CompositeKey> not just CompositeKey because one key say k1 can be in combination of 2 different set of k2 and k3.
Map<String, List<CompositeKey>> key1Index = new HashMap<>();
Map<Integer, List<CompositeKey>> key2Index = new HashMap<>();
Map<Double, List<CompositeKey>> key3Index = new HashMap<>();
然后是保存实际数据的数据图
Map<CompositeKey, Object> dataMap = new HashMap<>();
现在,假设您要对key1
添加key2
,key3
,Object
。创建CompositeKey
对象作为键
CompositeKey compositeKey = new CompositeKey(key1, key2, key3);
// Change value accordingly below
dataMap.put(compositeKey, new Object());
此外,更新索引图,以便以后可以使用它们查找
key1Index.computeIfAbsent(key1, k -> new ArrayList<>()).add(compositeKey);
key2Index.computeIfAbsent(key2, k -> new ArrayList<>()).add(compositeKey);
key3Index.computeIfAbsent(key3, k -> new ArrayList<>()).add(compositeKey);
最后,您现在可以
// Search by single key, say key1
List<CompositeKey> list = key1Index.get(key1);
List<Object> result = getResult(list, dataMap);
// Search by two keys, say key 1 and key 2
List<CompositeKey> key1IndexResult = key1Index.get(key1);
List<CompositeKey> key1Key2List = key1IndexResult.stream()
.filter(ck -> ck.getKey2().equals(key2))
.collect(Collectors.toList());
List<Object> key1Key2Result = getResult(key1Key2List, dataMap);
// Search by all 3 keys
CompositeKey allKeys = new CompositeKey(key1, key2, key3);
List<Object> allKeysResult = getResult(Collections.singletonList(allKeys), dataMap);
使用的实用方法:
private List<Object> getResult(List<CompositeKey> list, Map<CompositeKey, Object> dataMap) {
return list.stream().map(dataMap::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
工作代码在线链接:https://onlinegdb.com/rk2kszLMN