[英]How to create nested maps from flat sql select result set
具有類似於以下內容的 SQL 查詢:
SELECT DISTINCT REGION, COUNTRY, CITY
產生這個結果集
REGION COUNTRY CITY EUROPE FRANCE PARIS EUROPE FRANCE LYON EUROPE FRANCE NICE EUROPE GERMANY BERLIN EUROPE GERMANY DORTMUND EUROPE GERMANY HANNOVER
有沒有辦法使用谷歌的 ListMultimap 以便我最終得到一個鍵 -> 值 -> 值結構?
例如
{EUROPE
{GERMANY
{BERLIN, DORTMUND, HANNOVER},
FRANCE
{PARIS, LYON, NICE}
}
}
或者另一個包更適合這個?
編輯:
嘗試實施@Prog_G 的解決方案,但使用以下方法內存不足。 我認為最后我必須將外部轉換為另一種數據結構。 我會以某種方式從中創建地圖嗎? 附注。 真實的例子更深一層,但為了這個問題,想讓它更簡單。
private static class GeoRowMapper implements RowCallbackHandler {
ListMultimap<String, ListMultimap<String, ListMultimap<String, String>>> outer = ArrayListMultimap.create();
ListMultimap<String, ListMultimap<String, String>> middle = ArrayListMultimap.create();
ListMultimap<String, String> inner = ArrayListMultimap.create();
@Override
public void processRow(ResultSet rs) throws SQLException {
String region = rs.getString("region");
String country = rs.getString("country");
String city = rs.getString("city");
String address = rs.getString("address");
inner.put(city, address);
middle.put(country, inner);
outer.put(region, middle);
}
public ListMultimap<String, ListMultimap<String, ListMultimap<String, List<String>>>> get() {
return Multimaps.asMap(outer);
}
}
根據安迪特納的評論,您可以使用Table
。 在你的情況下,它會是這樣的:
ImmutableTable<Region, Country, ImmutableList<City>> immutableTable = RECORDS.stream()
.collect(toImmutableTable(
r -> r.getRegion(),
r -> r.getCountry(),
r -> ImmutableList.of(r.getCity()),
(l, l2) -> ImmutableList.<City>builder().addAll(l).addAll(l2).build()
));
或者,如果您想要可變表作為結果:
Table<Region, Country, List<City>> table = RECORDS.stream()
.collect(toTable(
r -> r.getRegion(),
r -> r.getCountry(),
r -> Lists.newArrayList(r.getCity()),
(l, l2) -> {
l.addAll(l2);
return l;
},
HashBasedTable::create
));
與作品stream()
和Collectors.groupingBy
(學分去這里,又見此)。 Set
而不是List
保證了唯一的元素。
Map<String, Map<String, Set<String>>> grouped =
records.stream()
.collect(Collectors.groupingBy(r -> r.region,
Collectors.groupingBy(r -> r.country,
Collectors.mapping(r -> r.city, Collectors.toSet()))));
給予
class Record {
String city;
String region;
String country;
}
目前,這實際上會給你HashMap
和一個HashSet
。 他們的問題是在迭代他們的條目時缺乏保證的順序。 如果結構應該支持用戶界面中顯示的樹,則您也沒有可用的重新排序或“在索引處插入”操作。 例如LinkedHashMap和TreeSet具有可預測的迭代順序。 在創建最終的樹數據結構時,這種方法仍然可以作為中間步驟。
根據您的口味, Map.computeIfAbsent
的使用可能是一個選項,它是在引入multimaps時引入的。
public Map<String, Map<String, Set<String>>> mumap(List<Record> records) {
Map<String, Map<String, Set<String>>> result = new LinkedHashMap<>();
for (Record r : records) {
result.computeIfAbsent(r.region, region -> new LinkedHashMap<>())
.computeIfAbsent(r.country, country -> new TreeSet<>())
.add(r.city);
}
return result;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.