带有映射和多个集合的Java 8流

带有映射和多个集合的Java 8流,java,foreach,hashmap,java-8,java-stream,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)) {

我正在尝试使用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>

但是它在forEach调用中,因此我不能将它返回到我的变量
distance
,因为它只为内部调用生成映射。我不明白。任何输入都会非常有用。谢谢

您可以使用
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));
Collection towns=getAllTowns(路线);
地图距离=towns.stream()
.filter(城镇->!originTown.equals(城镇))
.map(城镇->路线.stream()
.filter(route->route.hasOrigin(originTown)和&route.hasDestine(town))
.findFirst())
.filter(可选::isPresent)
.collect(toMap(route->route.get().getDestine(),route->route.get().getDistance());
城镇。溪流()
.filter(城镇->!距离.containsKey(城镇))
.forEach(城镇->距离.put(城镇,最大距离));
(请注意,
town
collect()
中不再可用,但您可以利用这样一个事实,即只有当每条路线的目的地城镇是
town
时,才能添加该路线)


还要注意,
toMap()
不接受重复的键。如果可以有多条路线到达任何城镇(我认为可能有),则应使用
groupingBy()

我认为您有两种选择来解决此问题。您可以事先创建生成的
映射
,然后使用嵌套的
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)));

嘿,所以,
toMap()
很好,因为城镇是通过它的名字来识别的,我真的不想要重复的钥匙。它工作得很好。谢谢还有一件事是:有什么好方法可以包含
distance.put(town,maxDistance)适用于不满足第二个过滤器要求的所有城镇。因为过滤后,我再也不能使用城镇对象了。谢谢!如果您希望所有条目都在地图中,那么首先为什么要过滤它们?(我可能不明白您想要实现什么;请澄清。)在第二个
for
循环中,有一个if语句,用于检查来源和目的地。如果不满意,则输入该城镇的
distance
地图
maxDistance
。在routes流上使用
过滤器
,可以很好地处理原始和目的地匹配的情况。但是我想知道如果它没有匹配项,我将如何在流中执行
“else”
操作。@felipe.forbeck:Gah,我没有看到那一行。那会更棘手;我认为最明确的解决办法可能是分两步进行;看看我更新的答案。太棒了!成功了。只需将其用于
collect
调用:
.collect(Collectors.toMap(route->route.isPresent()?route.get().getDestineTown():null,route->route.isPresent()?route.get().getDistance():0))
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));
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)));
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()));