algorithm - Convert Branch and Bound loop to use Java Stream API -


i have simple branch , bound algorithm works on variant of traveling salesman problem , thought fun try , convert use java 8 stream api. i'm having difficult time figuring out how without relying on side effects, however.

initial code

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 complete path, save     if(curr.getpath().size() == locations.size()) {         bestpath = curr.getpath();         bound = curr.getbound();         continue;     }     //incomplete path - add possible next steps     set<location> unvisited = new hashset<>(locations);     unvisited.removeall(curr.getpath());     (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);         }     } } 

i took first shot @ converting stream api , came following:

java 8 version

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; 

the main problem nodeconsumer has reference bestpath , bound, not final variables. make them final atomicreference variables work around this, feel sort of violates spirit of stream api. can me distill initial algorithm more idiomatic implementation?

i wonder if using reduce way go this, allows track values without need external variables.

something following (i've had guess @ few of details of above code, i'm on right track).

    final bifunction<entry<integer, list<location>>, node, entry<integer, list<location>>> accumulator         = (identity, node) -> {             if (node.getpath().size() == locations.size() ) {                 return new simpleentry<>(node.getbound(), node.getpath());             } else {                 locations.stream()                     .filter(l -> !node.getpath().contains(l))                     .map(l -> {                         list<location> newpath = new arraylist<>(node.getpath());                         newpath.add(l);                         return new node(newpath, getboundforpath(newpath));                     })                     .filter(newnode -> newnode.getbound() <= identity.getkey())                     .foreach(queue::add);                 return identity;             }         };      final binaryoperator<entry<integer, list<location>>> combiner         = (left, right) -> left.getkey() < right.getkey() ? left : right;      final entry<integer, list<location>> identity         = new simpleentry<>(integer.max_value, null);      final list<location> bestvalue = stream.generate(queue::poll)         .reduce(identity, accumulator, combiner)         .getvalue(); 

alternatively, @ using seq in jooλ (a sequential extension streams), , use foldleft instead.


Comments

Popular posts from this blog

java - WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/board/] in DispatcherServlet with name 'appServlet' -

android - How to create dynamically Fragment pager adapter -

1111. appearing after print sequence - php -