【发布时间】:2015-09-30 00:42:20
【问题描述】:
我有一个简单的分支定界算法,它适用于旅行商问题的变体,我认为尝试将其转换为使用 Java 8 Stream API 会很有趣。但是,我很难弄清楚如何在不依赖副作用的情况下做到这一点。
初始代码
int bound = Integer.MAX_VALUE;
List<Location> bestPath = null;
while(!queue.isEmpty()) {
Node curr = queue.poll();
//bound exceeds best, bail
if (curr.getBound() >= bound) {
return bestPath;
}
//have a complete path, save it
if(curr.getPath().size() == locations.size()) {
bestPath = curr.getPath();
bound = curr.getBound();
continue;
}
//incomplete path - add all possible next steps
Set<Location> unvisited = new HashSet<>(locations);
unvisited.removeAll(curr.getPath());
for (Location l : unvisited) {
List<Location> newPath = new ArrayList<>(curr.getPath());
newPath.add(l);
Node newNode = new Node(newPath, getBoundForPath(newPath));
if (newNode.getBound() <= bound){
queue.add(newNode);
}
}
}
我第一次尝试将其转换为 Stream API 并提出以下建议:
Java 8 版本
Consumer<Node> nodeConsumer = node -> {
if(node.getPath().size() == locations.size() ) {
bestPath = node.getPath();
bound = node.getBound();
} else {
locations.stream()
.filter(l -> !node.getPath().contains(l))
.map(l -> {
List<Location> newPath = new ArrayList<>(node.getPath());
newPath.add(s);
return new Node(newPath, getBoundForPath(newPath));
})
.filter(newNode -> newNode.getBound() <= bound)
.forEach(queue::add);
}
};
Stream.generate(() -> queue.poll())
.peek(nodeConsumer)
.filter(s -> s.getBound() > bound)
.findFirst();
return bestPath;
主要问题是 nodeConsumer 必须引用 bestPath 和 bound,它们不是 final 变量。我可以让它们成为最终的 AtomicReference 变量来解决这个问题,但我觉得这违反了流 API 的精神。谁能帮我将初始算法提炼成更惯用的实现?
【问题讨论】:
-
我不认为你可以在不滥用 API 的情况下获得更好的东西。 Stream API 不适用于此类算法。不过这个问题很有趣。
-
@TagirValeev 感谢您的回复。仍然习惯于我可用的新选项,并且很难确定某件事是因为我做错了而困难,还是因为它不是理想的用法而困难。
标签: java algorithm lambda java-8 java-stream