繁体   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