簡體   English   中英

如何從平面 sql 選擇結果集創建嵌套映射

[英]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 他們的問題是在迭代他們的條目時缺乏保證的順序。 如果結構應該支持用戶界面中顯示的樹,則您也沒有可用的重新排序或“在索引處插入”操作。 例如LinkedHashMapTreeSet具有可預測的迭代順序。 在創建最終的樹數據結構時,這種方法仍然可以作為中間步驟。

根據您的口味, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM