我很惊讶没有类似boost多索引容器的版本可用(也许有,只是我不知道)。但在Java中自己编写一个版本并不太难。
一个简单但可行的版本可能如下所示:
基本网站对象
我使用了略有不同的Site对象,只是为了保持简单(因为我在公交车上无法访问此帖子...)
public class Site {
Integer id;
String name;
String rating;
}
一个封装的版本
我稍后将介绍一些实用的类,但它们有点丑陋。这只是为了展示在稍微封装一下之后最终接口会变得更加易于理解:
class SiteRepository {
private final MultiMap<Site> sites = new MultiMap<>();
public final AbstractMap<String, Site> byName = sites.addIndex((site)->site.name);
public final AbstractMap<Integer,Site> byId = sites.addIndex((site)->site.id);
public final AbstractMap<String,List<Site>> byRating = sites.addMultiIndex((Site site)->site.rating);
public void add(Site s) { sites.add(s); }
}
SiteRepository repo = new SiteRepository();
repo.add(...);
Site site = repo.byId.get(1234);
repo.byId.forEach((Integer id, Site s) -> System.err.printf(" %s => %s\n", id, s));
MultiMap核心
可能应该被称为MultiIndex
,因为MultiMap
有其他含义...
public static class MultiMap<V> {
public static class MultiMapIndex<K,V> extends AbstractMap<K,V> {
@Override
public Set<Entry<K, V>> entrySet() {
return map.entrySet();
}
HashMap<K,V> map = new HashMap<>();
}
public <K> MultiMapIndex<K,V> addIndex(Function<V, K> f) {
MultiMapIndex<K,V> result = new MultiMapIndex<>();
Consumer<V> e = (V v) -> result.map.put(f.apply(v), v);
mappers.add(e);
values.forEach(e);
return result;
}
public <K> MultiMapIndex<K,List<V>> addMultiIndex(Function<V, K> f) {
MultiMapIndex<K,List<V>> result = new MultiMapIndex<>();
Consumer<V> e = (V v) -> {
K key = f.apply(v);
List<V> list = result.map.get(key);
if (list == null) {
list = new ArrayList<>();
result.map.put(key, list);
}
list.add(v);
};
mappers.add(e);
values.forEach(e);
return result;
}
public void add(V v) {
values.add(v);
mappers.forEach( e -> e.accept(v));
}
private List<Consumer<V>> mappers = new ArrayList<>();
private List<V> values = new ArrayList<>();
}
更多底层示例
public static void main(String[] args) {
MultiMap<Site> multiMap = new MultiMap<>();
MultiMapIndex<Integer, Site> byId = multiMap.addIndex((site)->site.id);
multiMap.add(new Site(1234,"A Site","A"));
multiMap.add(new Site(4321,"Another Site","B"));
multiMap.add(new Site(7777,"My Site","A"));
MultiMapIndex<String, Site> byName = multiMap.addIndex((site)->site.name);
System.err.printf("Get by id=7777 = %s\n", byId.get(7777));
System.err.printf("Get by name='A Site' = %s\n", byName.get("A Site"));
System.err.printf("byId.keys() = %s\n", byId.keySet());
byId.forEach((Integer id, Site s) -> System.err.printf(" %s => %s\n", id, s));
MultiMapIndex<String, List<Site>> byRating = multiMap.addMultiIndex((Site site)->site.rating);
System.err.printf("byRating('A') = %s\n", byRating.get("A"));
System.err.printf("byRating('B') = %s\n", byRating.get("B"));
multiMap.add(new Site(3333,"Last Site","B"));
System.err.printf("byRating('A') = %s\n", byRating.get("A"));
System.err.printf("byRating('B') = %s\n", byRating.get("B"));
}
}
parentBrand
?为什么不是HashMap<String, ParentBrand>
而是HashMap<String, Site>
等等。 - AndremoniyparentBrandToSiteMap
中的键不能等于siteNameToSiteMap
中的任何键),则可以使用单个HashMap<String,Site>
存储所有关联(每个Site
将由最多 3 个键索引)。这将需要在将站点 ID 放入单个映射时将其转换为字符串。 - Eran