繁体   English   中英

如何过滤地图并返回值列表

[英]How to filter map and return list of values

我正在尝试创建一个函数来过滤一个映射,该映射包含一个字符串作为键和一个 Flight 对象列表作为值并返回一个字符串列表。 地图代表飞行路径,任务是找到从起点到终点的最短路径。 航班类有两个字段,origin 和 destination。 所以如果我发送给纽约的维也纳,我应该得到一个包含 fligth1 和 flight2 的列表。 该函数接受两个参数(字符串来源,字符串目的地)

地图中的键代表一个城市,而值是航班到达的位置,如下所示:

Map<String, List<Flight>> paths = new HashMap<>();

List<Flight> flightsToBerlin = new ArrayList<>();
List<Flight> flightsToVienna = new ArrayList<>();

Flight flight1 = new Flight("Vienna", "Berlin");
Flight flight2 = new Flight("Berlin", "New York");

flightsToBerlin.add(flight1);
flightsToVienna.add(flight2);


paths.put("Vienna", flightsToVienna);
paths.put("Berlin", flightsToBerlin);

诀窍是要求它在一行中完成。 这是让我发疯的部分。 我曾尝试使用流,但在过滤地图并找到目的地后我有点困惑,如下所示:

public List<Flight> findPath(String origin, String destination) {
    return (List<Flight>) this.paths.entrySet().stream()
            .filter(x -> x.getKey().equals(destination))..
}

我如何从这里开始?

你可以这样做:

return Stream.of(
        paths.values()
                .stream()
                .flatMap(Collection::stream)
                .collect(Collectors.groupingBy(Flight::getStartingLocation))
).flatMap(flights ->
        Stream.of(
                new HashMap<>(Map.of(origin, new Flight(origin, origin)))
        ).peek(back ->
                Stream.iterate(
                        List.of(origin),
                        list -> list.stream().flatMap(
                                now -> flights.getOrDefault(now, Collections.emptyList()).stream()
                                        .filter(flight -> back.putIfAbsent(flight.getDestination(), flight) == null)
                                        .map(Flight::getDestination)
                        ).collect(Collectors.toList())
                ).filter(list -> list.contains(destination)).findFirst()
        ).map(back ->
                Stream.iterate(
                        new Flight(destination, null),
                        now -> back.get(now.getStartingLocation())
                )
                        .skip(1)
                        .takeWhile(flight -> !flight.getDestination().equals(origin))
                        .collect(Collectors.toList())
        )
)
        .map(ArrayList::new)
        .peek(Collections::reverse)
        .findFirst().get();

试试下面的代码:

return (List<Flight>) paths.entrySet()
                    .stream()
                    .filter(x -> x.getKey().equals(destination))
                    .map(Map.Entry::getValue)
                    .flatMap(List::stream) 
                    .collect(Collectors.toList());

你所要求的几乎是不可能的。 但是,我能够制作出一种大多数情况下有效的单线。 它的主要限制是它只能找到两个航班才能让您到达目的地。 换句话说:

Berlin   -> Vienna                       | WORKS 
New York -> Berlin   -> Vienna           | WORKS
Boston   -> New York -> Berlin -> Vienna | DOESN'T WORK

我通常会花时间解释我在回答中做了什么以及为什么,但这是 Java 语言中如此凌乱、复杂、低效的可憎之处,我怀疑我是否能很好地解释它。 以下是在解释发生了什么事我最好的尝试,但不是为什么它正在发生:

  1. 查找与给定始发地或目的地匹配的航班
  2. 检查与给定始发地和目的地都匹配的单个航班
  3. 如果没有匹配给定起点和目的地的航班,则比较每个匹配起点或目的地的航班,看看是否有任何航班与给定的参数和给定的参数同时匹配。 例子:

     (A1) (A2) findPath(Boston, Tokyo) (B1) (B2) B1 aligns with A1 Flight[Boston, Istanbul] C2 aligns with A2 C1 aligns with B2 (C1) (C2) Flight[Istanbul, Tokyo]

在实现代码之前,您将需要以下导入:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream; 

我还假设您的Flight类看起来像这样:

public class Flight {

    private String origin;
    private String dest;

    public Flight(String origin, String dest) {
        this.origin = origin;
        this.dest = dest;
    }

    public String getOrigin() {
        return origin;
    }

    public String getDestination() {
        return dest;
    }

}

好的,这是你的单线:

@SuppressWarnings("unchecked")
public List<Flight> findPath(String origin, String destination) {
    return new ArrayList<Flight>((Collection<Flight>) this.paths.values().stream().map(l -> l.stream().filter(f -> f.getDestination().equalsIgnoreCase(destination)|| f.getOrigin().equalsIgnoreCase(origin)).collect(Collectors.toList())).map(t -> new Object[] { t.stream().filter(f -> f.getDestination().equalsIgnoreCase(destination)&& f.getOrigin().equalsIgnoreCase(origin)).findAny(), t }).map(t -> ((Optional<Flight>) t[0]).isPresent() ? ((Optional<Flight>) t[0]).get() : t[1]).reduce((t, u) -> t instanceof Flight ? new HashSet<Flight>(Arrays.asList((Flight) t)): t instanceof HashSet ? t: u instanceof Flight ? new HashSet<Flight>(Arrays.asList((Flight) u)): u instanceof HashSet ? u: Stream.concat(((List<Flight>) t).stream().filter(f1 -> (f1.getDestination().equalsIgnoreCase(destination)&& ((List<Flight>) u).stream().anyMatch(f2 -> f1.getOrigin().equalsIgnoreCase(f2.getDestination())))|| (f1.getOrigin().equalsIgnoreCase(origin)&& ((List<Flight>) u).stream().anyMatch(f2 -> f1.getDestination().equalsIgnoreCase(f2.getOrigin())))),((List<Flight>) u).stream().filter(f1 -> (f1.getDestination().equalsIgnoreCase(destination)&& ((List<Flight>) t).stream().anyMatch(f2 -> f1.getOrigin().equalsIgnoreCase(f2.getDestination())))|| (f1.getOrigin().equalsIgnoreCase(origin)&& ((List<Flight>) t).stream().anyMatch(f2 -> f1.getDestination().equalsIgnoreCase(f2.getOrigin()))))).collect(Collectors.toList())).get());
}

暂无
暂无

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

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