我正在尝试创建一个函数,该函数过滤一个映射,该映射将String作为键,将Flight对象列表作为值,并返回字符串列表。该地图代表飞行路线,任务是找到从起点到目的地的最短路径。 飞行班级有两个字段,始发地和目的地。因此,如果我将邮件发送给纽约维也纳,我应该得到一个列表,其中包含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))..
}
如何从这里继续?
答案 0 :(得分:3)
您可以这样做:
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();
答案 1 :(得分:2)
您要的几乎是不可能的。但是,我能够制造出一种通常能起作用的单线纸。它的主要限制是只能找到两次将您带到目的地的航班。换句话说:
Berlin -> Vienna | WORKS
New York -> Berlin -> Vienna | WORKS
Boston -> New York -> Berlin -> Vienna | DOESN'T WORK
我通常花时间解释我在回答中所做的事情以及原因,但这是对Java语言的如此混乱,复杂,效率低下的可憎之处,我怀疑我能否对它做充分的解释。这是我尽力解释发生什么的尝试,但不是解释为什么发生的原因:
如果没有同时符合给定起点和终点的航班,则比较与起点或终点相匹配的每个航班,并查看是否有航班与对方以及给定参数同时对齐。示例:
(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());
}
答案 2 :(得分:1)
尝试以下代码:
return (List<Flight>) paths.entrySet()
.stream()
.filter(x -> x.getKey().equals(destination))
.map(Map.Entry::getValue)
.flatMap(List::stream)
.collect(Collectors.toList());