8
我有一個簡單的分支和綁定算法,適用於Traveling Salesman問題的變體,我認爲嘗試將其轉換爲使用Java 8 Stream API 。然而,我很難搞清楚如何去做,而不依賴副作用。將分支和綁定循環轉換爲使用Java 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);
}
}
}
我拍了第一張照片,在將其轉換爲流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,它們是不是最終的變數。我可以讓它們成爲最終的AtomicReference變量來解決這個問題,但是我覺得這種做法違反了流API的精神。任何人都可以幫助我將最初的算法提煉成更加慣用的實現嗎?
我不認爲你可以得到更好的東西,而不濫用API。 Stream API不適用於此類算法。不過,這個問題很有趣。 –
@TagirValeev感謝您的回覆。我仍然習慣了可用的新選項,並且難以確定事情是否困難,因爲我做錯了,或者因爲它不是一個理想的用法而困難。 –