Java 8 implementation for recursive method - java

What is the correct way of using lambdas for a recursive method? I have been trying to write a depth-first-search recursive function for a Graph. I have tried implementing the Lambda version, but not sure if my implementation is the correct way of using it in a recursive function.
Outline of the code:
a) Old fashioned way
private void depthFirstSearch(final Graph graph, final int sourceVertex){
count++;
marked[sourceVertex]= true;
for(int vertex:graph.getAllVerticesConnectedTo(sourceVertex)){
if(marked[vertex]!=true){
edgeTo[vertex]=sourceVertex;
depthFirstSearch(graph,vertex);
}
}
}
b) Java 8 Lambdas way:
private void depthFirstSearchJava8(final Graph graph, final int sourceVertex){
count++;
marked[sourceVertex]= true;
StreamSupport.stream(graph.getAllVerticesConnectedTo(sourceVertex).spliterator(),false)
.forEach(vertex -> {
if(marked[vertex]!=true){
edgeTo[vertex]=sourceVertex;
depthFirstSearchJava8(graph,sourceVertex);
}
});
}
I have tried to write a lambda version as above but could not figure out the advantage it is providing as compared to the traditional way.
Thanks

Just because lambdas exist, this doesn't mean you have to use them everywhere.
You are looping over an iterable, without filtering or mapping or transforming anything (which are the typical use cases for lambdas).
The for loop does what you want in a one-liner. Therefore, lambdas should not be used here.

That's because there is no advantage, at least not in this case. Lambdas are useful when you want to create a small function to be used in just one place in the program, e.g. when passing the lambda as an argument for another function. If your lambda takes more than one line of code, you should reconsider the idea of using it.

You could rewrite your depthFirstSearch method as follows:
private void depthFirstSearchJava8(Graph graph, int sourceVertex){
count++;
marked[sourceVertex] = true;
graph.getAllVerticesConnectedTo(sourceVertex).stream()
.filter(vertex -> !marked[vertex])
.peek(vertex -> edgeTo[vertex] = sourceVertex)
.forEach(vertex -> depthFirstSearchJava8(graph, vertex));
}
This code assumes getAllVerticesConnectedTo() method returns a collection of integers. If it returns an array of integers instead, then use the following code:
private void depthFirstSearchJava8(Graph graph, int sourceVertex){
count++;
marked[sourceVertex] = true;
Arrays.stream(graph.getAllVerticesConnectedTo(sourceVertex))
.filter(vertex -> !marked[vertex])
.peek(vertex -> edgeTo[vertex] = sourceVertex)
.forEach(vertex -> depthFirstSearchJava8(graph, vertex));
}
In the first solution, I've used the Collection.stream() method to get a stream of connected vertices, while in the second one, I've used the Arrays.stream() method. Then, in both solutions, I've first used filter() to keep only non marked vertices and peek() to modify the edgeTo array. Finally, forEach() is used to terminate the stream by invoking depthFirstSearchJava8() method recursively.

Related

Java stream elegant solution to avoid looping multiple times

class Note{
private text;
..
private int score = 0;
}
class Project{
...
List<Note> notes;
private int score = 0;
}
Project score is derived by project properties + sum of note scores.
First I'm updating and replacing all notes in the project. Then iterating again to sum the note score.
project.notes(project.notes()
.stream()
.map(this::updateNote)
.collect(Collectors.toList()));
project.score(project.notes()
.stream()
.mapToInt(n->n.score())
.sum());
private Note updateNote(Note note){
note.score(....);
return note;
}
Somehow I feel this is not right. Is there an elegant solution to avoid looping twice?
Performing a side-effect-ful method in a map operation like this is suspect no matter how you want to slice this puzzle, it's always going to look a bit weird.
You're abusing map here: You map objects to itself, but in so doing, cause a side effect. well, in for a penny, in for a pound, I guess - that is the suspect thing here, but the code works (it's just bad style). Note also that passing the collected list to project.notes does nothing, just project.notes().stream().map(this::updateNote).collect(Collectors.toList()) and letting the collection be lost to the either already 'works'. The only point of collecting is merely to force the stream to actually iterate (map doesn't cause iteration, it merely says: When you start iterating, map as-you-go).
So:
project.notes()
.stream()
.map(this::updateNote)) // no-op streamwise. Just making the side effect happen
.mapToInt(this::score)
.sum();
is all you need - but it's.. still a bit stinky. If instead of updateNote, note was immutable and there is a calculateScore method, you could do:
project.notes()
.stream()
.mapToInt(this::calculateScore)
.sum()
Here, calculateScore doesn't change anything about a Note object, it merely.. calculates the score and returns it, without changing any fields.
EDIT: I forgot a 'stream' in stream, and added a clarification.
You may get rid of looping twice by accumulating the sum in an AtomicInteger, but this would result in replacing the method reference this::updateNote with a lambda:
AtomicInteger sum = new AtomicInteger(0);
project.notes(project.notes()
.stream()
.map(note -> {
Note updated = updateNote(note);
sum.addAndGet(updated.getScore());
return updated;
})
.collect(Collectors.toList()));
project.score(sum.intValue());

In Java, a "decorate and sort" concise implementation?

I'm learning Java for the first time (my prior experience is Python and Haskell). I have a situation that would, in Python, require a "decorate and sort" idiom. Such as the following (code not tested but this is roughly correct):
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
By choosing a different evalFunc you can choose how this is sorted.
In Java, I'm writing a program that composes music by choosing from among a list of notes, evaluating the "fitness" of each note, and picking the best. I have a class representing musical notes:
class Note {
...
}
I have a class that represents the fitness of a note as two values, its goodness and badness (yes, these are separate concepts in my program). Note: in Python or Haskell, this would simply be a 2-tuple, but my understanding is that Java doesn't have tuples in the usual sense. I could make it a pair, but it gets unwieldy to declare variables all over the place like List<Pair<Type1,Pair<Type2,Type3>>>. (As an aside, I don't think Java has type aliases either, which would let me shorten the declarations.)
class Fitness {
double goodness;
double badness;
}
The function that evaluates the fitness needs access to several pieces of data other than the Note. We'll say it's part of a "Composition" class:
class Composition {
... data declared here ... ;
public Fitness evaluate(Note n) {
}
}
I'd like to be able to compare Fitness objects in numerical order. There are two ways to compare: either goodness or badness can be numerically compared, depending on the situation.
class CompareFitnessByGoodness implements Comparator<Fitness> {
}
class CompareFitnessByBadness implements Comparator<Fitness> {
}
I'd like to package the Note together with its fitness, so I can sort the combined list by fitness and later pull out the best Note.
class Together {
public Note;
public Fitness;
}
I'd like to sort a List<Together> by either the goodness, or by the badness. So I might need:
class CompareTogetherByGoodness implements Comparator<Together> {
...
}
class CompareTogetherByBadness implements Comparator<Together> {
...
}
Eventually I'll write something like
Note pickBest(List<Together> notes) {
// Pick a note that's not too bad, and pretty good at the same
// time.
// First sort in order of increasing badness, so I can choose
// the bottom half for the next stage (i.e. the half "least bad"
// notes).
Collections.sort(notes, new CompareTogetherByBadness());
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
// Now sort `leastBadHalf` and take the last note: the one with
// highest goodness.
Collections.sort(leastBadHalf, new CompareTogetherByGoodness());
return leastBadHalf.get(leastBadHalf.size()-1);
}
Whew! That is a LOT of code for something that would be a few lines in Haskell or Python. Is there a better way to do this?
EDIT:
Addressing some of the answers.
"You don't need to decorate." Well, my fitness computation is very expensive, so I want to compute it once for each note, and save the result for later access as well.
"Store goodness/badness in Note." The goodness or badness is not a property of the note alone; it's only meaningful in context and it can change. So this is a suggestion that I add mutable state which is only meaningful in some contexts, or plain wrong if there's a bug which accidentally mutates it. That's ugly, but maybe a necessary crutch for Java.
Going by what you already have
origList = <something>
decorated = sorted( [(evalFunc(item), item) for item in origList] )
finalList = [item for _, item in decorated]
This is the equivalent in modern Java:
Given your composition object:
Composition composer = ...;
And a list of notes:
List<Note> notes = ...;
Then you can do:
List<Together> notesAllTogetherNow = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByGoodness())
.collect(Collectors.toList());
To get the best note, you can take a bit further:
Optional<Note> bestNote = notes.stream()
.map(note -> new Together(note, composer.evaluate(note)))
.sorted(new CompareTogetherByBadness())
.limit(notes.size() / 2) // Taking the top half
.sorted(new CompareTogetherByGoodness())
.findFirst() // Assuming the last comparator sorts in descending order
.map(Together::getNote);
You can use streams:
Function<Foo, Bar> func = ...
Comparator<Foo> comparator = ...
var list = ...
var sorted = list.stream()
.sorted(comparator)
.map(func)
.collect(Collectors.toList());
Java plainly includes a Collections.sort :: List -> Comparator -> List that does everything for you. It mutates the original list, though.
Unfortunately, Java's standard library does not include tuples and even a plain Pair; the Apache Commnons library does, though.
In short, you don't need the decorate / undecorate approach in Java.
class Fitness {
double goodness;
double badness;
}
class Together {
Note note;
Fitness fitness;
}
class Note{
}
List<Together> notes = ...
Collections.sort(notes, Comparator.comparingDouble(value -> value.fitness.badness));
List<Together> leastBadHalf = notes.subList(0, notes.size()/2);
return leastBadHalf.stream().max(Comparator.comparingDouble(value -> value.fitness.goodness));

Recursive Streaming API

I'm currently working on a small graph theory algorithm, which uses a recursive Depth-First Search.
Since it's recursive, I'm asking myself, if I should use the Stream API to perform such a task or use Iterators and for each Loops.
This is my code:
private void processNext(Node node) {
//METHOD A
for (Node neighbour : node) {
if (!connectedNodes.contains(neighbour)) {
connectedNodes.add(neighbour);
processNext(neighbour);
}
}
//OR METHOD B
node.getNodes().stream().filter(not(connectedNodes::contains)).forEach(e -> {
connectedNodes.add(e);
processNext(e);
});
//OR METHOD C
node.getNodes().stream().forEach(e -> {
if (!connectedNodes.contains(e)) {
connectedNodes.add(e);
processNext(e);
}
});
}
Method A and C will work 100% intended, but I'm not sure about B...
Does the filter method in the streaming API filter non matching objects out before foreach or while foreach? (Do B and C the exact same thing?)
And which Method will be the fastest?
Any help is apreciated!
OK Method B and C work exactly the same!
Not sure if the iterator way is faster, but since B requires less space, I'm going for that one!

Is it possible to write a loop in Java that does not actually use a loop method?

I was curious if, in Java, you could create a piece of code that keeps iterating a piece of code without the use of a for or while loop, and if so, what methods could be used to solve this?
Look at recursion. A recursive function is a function which calls itself until a base case is reached. An example is the factorial function:
int fact(int n)
{
int result;
if(n==1)
return 1;
result = fact(n-1) * n;
return result;
}
You could use the Java 8 Streams methods for iterating over the elements of a Collection. Among the methods you can use are filtering methods (get all the elements of a collection that satisfy some conditions), mapping methods (map a Collection of one type to a Collection of another type) and aggregation methods (like computing the sum of all the elements in a Collection, based on some integer member of the Element stored in the collection).
For example - Stream forEach :
List<Element> = new ArrayList<Element>();
...
list.stream().forEach (element -> System.out.println(element));
Or you can do it without a Stream :
List<Element> = new ArrayList<Element>();
...
list.forEach (element -> System.out.println(element));
Another variant of recursion:
public class LoopException extends Exception {
public LoopException(int i, int max) throws LoopException {
System.out.println( "Loop variable: "+i);
if (i < max)
throw new LoopException( i+1, max );
}
}
Of course this is just a bit of fun, don't ever do it for real.
Java does not have a goto statement (that's a lie), so that way is a dead end.
But you could always make a piece of code endlessly iterate using recursion. Old factorial function seems to be the favorite, but since it is not an infinite loop, I will go for this simple function:
int blowMyStack(int a) {
return blowMyStack(a + 1);
}
There will be many ways to do this using various features of the language. But it always falls to an underlying recursion.
In case you're referring of something like C's goto, the answer is no.
In other cases, you can use recursive functions.

Java Lambda Expression for if condition - not expected here

Consider the case where an if condition needs to evaluate an array or a List. A simple example: check if all elements are true. But I'm looking for generic way to do it
Normally I'd do it like that:
boolean allTrue = true;
for (Boolean bool : bools){
if (!bool) {
allTrue = false;
break;
}
}
if (allTrue){
// do Something
}
But now I'd like to hide it into my if condition. I tried using Lambda Expressions for this, but it's not working:
if (() -> {
for (Boolean bool : bools)
if (!bool)
return false;
return true;
}){
// do something
}
If this were working I could do something more complicated like
if (() -> {
int number = 0;
for (MyObject myobject : myobjects)
if (myObject.getNumber() != 0)
numbers++;
if (numbers > 2)
return false;
return true;
}{
//do something
}
Is there a better way to do it is it just a syntax error?
UPDATE
I'm not talking about the boolean array, rather looking for a generic way to achieve that.
You can write, given for instance a List<Boolean>:
if (!list.stream().allMatch(x -> x)) {
// not every member is true
}
Or:
if (list.stream().anyMatch(x -> !x)) {
// at least one member is false
}
If you have an array of booleans, then use Arrays.stream() to obtain a stream out of it instead.
More generally, for a Stream providing elements of (generic) type X, you have to provide a Predicate<? super X> to .{all,any}Match() (either a "full" predicate, or a lambda, or a method reference -- many things go). The return value of these methods are self explanatory -- I think.
Now, to count elements which obey a certain predicate, you have .count(), which you can combine with .filter() -- which also takes (whatever is) a Predicate as an argument. For instance checking if you have more than 2 elements in a List<String> whose length is greater than 5 you'd do:
if (list.stream().filter(s -> s.length() > 5).count() > 2L) {
// Yup...
}
Your problem
Your current problem is that you use directly a lambda expression. Lambdas are instances of functional interfaces. Your lambda does not have the boolean type, that's why your if does not accept it.
This special case's solution
You can use a stream from your collections of booleans here.
if (bools.stream().allMatch((Boolean b)->b)) {
// do something
}
It is actually much more powerful than this, but this does the trick I believe.
General hint
Basically, since you want an if condition, you want a boolean result.
Since your result depends on a collection, you can use Java 8 streams on collections.
Java 8 streams allow you to do many operations on a collection, and finish with a terminal operation. You can do whatever complicated stuff you want with Stream's non-terminal operations. In the end you need one of 2 things:
use a terminal operation that returns a boolean (such as allMatch, anyMatch...), and you're done
use any terminal operation, but use it in a boolean expression, such as myStream.filter(...).limit(...).count() > 2
You should have a look at your possibilities in this Stream documentation or this one.

Categories