简体   繁体   English

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

[英]Java 8 Stream with map and multiples sets

I am trying to write these lines using java8 streams: 我试图使用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>

The result that I got so far is: 到目前为止我得到的结果是:

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;

How can I collect after the inner filter and build the Map< Town,Integer> where the integer is the route.getDistance()? 如何在内部过滤器之后收集并构建Map <Town,Integer>,其中整数是route.getDistance()? I tried to use: 我试着用:

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

But it is inside the forEach call, then I can't return it to my variable distances because it generates the map only for the inner call. 但它在forEach调用中,然后我不能将它返回到我的可变distances因为它只为内部调用生成映射。 I did not understand it. 我不明白。 Any input would be really helpful. 任何输入都会非常有用。 Thanks. 谢谢。

You can use findFirst() to build a list that contains, for each town, the first route that has that town as the destination, and then call toMap() on it. 您可以使用findFirst()来构建一个列表,该列表为每个城镇包含将该城镇作为目标的第一条路线,然后在其上调用toMap() The default values for missing cities can be handled separately. 缺失城市的默认值可以单独处理。

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));

(Note that town is no longer available in collect() , but you can take advantage of the fact that each route got added only if its destination town was town .) (请注意, collect()不再提供town ,但您可以利用每条路线仅在其目的地城镇为town时才添加的事实。)

Also note that toMap() doesn't accept duplicate keys. 另请注意, toMap()不接受重复键。 If there can be multiple routes to any town (which I assume there might be), you should use groupingBy() instead. 如果可以有多条路线到任何城镇(我假设可能有),你应该使用groupingBy()代替。

I think you have two options to solve this. 我认为你有两个选择来解决这个问题。 Either you create your resulting Map beforehand and use nested foreach s: 您可以事先创建生成的Map并使用嵌套的foreach

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)));

The other option is to collect your stream to a Map by creating an intermediate Object which is essentially a Pair of Town and Integer : 另一个选项是通过创建一个中间Objectcollect您的流到Map ,该Object本质上是一对TownInteger

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())); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM