带有地图和倍数集的Java 8 Stream

时间:2016-08-20 01:28:46

标签: java foreach hashmap java-8 java-stream

我正在尝试使用java8流编写这些行:

    for (Town town : getAllTowns(routes)) {

        if (originTown.equals(town))
            continue;

        for (Route route : routes) {
            if (route.hasOrigin(originTown) && route.hasDestine(town)) {
                distances.put(town, route.getDistance());
                break;
            }
            distances.put(town, maxDistance);
        }
    }
    return distances; //Map<Town,Integer>

到目前为止我得到的结果是:

Map<Town, Integer> distances = getAllTowns(routes).stream()
.filter(town -> !originTown.equals(town))
.forEach(town -> routes.stream()
        .filter(route -> route.hasOrigin(originTown) && route.hasDestine(town)
        ...)
return distances;

如何在内部过滤器之后收集并构建Map&lt;镇,整型&GT;其中整数是route.getDistance()? 我试着用:

.collect(Collectors.toMap(route -> route.getDestineTown(), route -> route.getDistance()))

但它在forEach调用中,然后我无法将其返回到我的变量distances,因为它仅为内部调用生成映射。我不明白。任何输入都会非常有用。谢谢。

2 个答案:

答案 0 :(得分:2)

您可以使用findFirst()构建一个列表,其中包含针对每个城镇的第一条路线,该路线将该城镇作为目的地,然后在其上调用toMap()。缺失城市的默认值可以单独处理。

Collection<Town> towns = getAllTowns(routes);
Map<Town, Integer> distances = towns.stream()
    .filter(town -> !originTown.equals(town))
    .map(town -> routes.stream()
        .filter(route -> route.hasOrigin(originTown) && route.hasDestine(town))
        .findFirst())
    .filter(Optional::isPresent)
    .collect(toMap(route -> route.get().getDestine(), route -> route.get().getDistance()));
towns.stream()
    .filter(town -> !distances.containsKey(town))
    .forEach(town -> distances.put(town, maxDistance));

(请注意town中不再提供collect(),但您可以利用每条路线仅在其目的地城镇为town时才会添加的事实。)

另请注意,toMap()不接受重复的密钥。如果可以有多条路线到任何城镇(我假设可能有),您应该使用groupingBy()代替。

答案 1 :(得分:1)

我认为您有两种方法可以解决这个问题。您可以事先创建结果Map并使用嵌套的foreach s:

Map<Town, Integer> distances = new HashMap<>();
    getAllTowns(routes).stream().filter(town -> !originTown.equals(town))
            .forEach(town -> routes.stream().forEach(route -> distances.put(town,
                    route.hasOrigin(originTown) && route.hasDestine(town) ? route.getDistance() : maxDistance)));

另一个选项是collect您的信息流为Map,方法是创建一个中间Object,它基本上是一对TownInteger:< / p>

Map<Town, Integer> distances = getAllTowns(routes).stream().filter(town -> !originTown.equals(town))
            .flatMap(town -> routes.stream()
                    .map(route -> new AbstractMap.SimpleEntry<Town, Integer>(town,
                            route.hasOrigin(originTown) && route.hasDestine(town) ? route.getDistance()
                                    : maxDistance)))
            .collect(Collectors.toMap(entry -> entry.getKey(), entry -> entry.getValue()));