Harry Blargle
Harry Blargle

Reputation: 426

Finding an object with the lowest value and returning the object, not the value, with a stream

I currently find the object with the lowest value like this:

List<Location> locations = new ArrayList<Location>();
RGB colour = new RGB(5,3,7);
Location best = null;
double bestscore = 0.0;
for(Location loc : locations)
{
  if(best == null)
  {
    best = loc;
    bestscore = getScore(loc,colour, average);
  }
  else
  {
    double oscore = getScore(loc,colour, average);
    if(oscore < bestscore)
    {
      best = loc;
      bestscore = oscore;
    }
  }
}

where getScore is:

double getScore(Location loc, RGB colour, boolean average)

This is pretty slow considering locations usually has a few thousand entries and this loop is used a few million times in a row.

So I wanted to try and use the new parallelStream() from java 8. I made a comparator that compares getScore values.

Location best = locations.parallelStream().min(new ComparatorScoreDif(colour)).get();

Am I going in the right direction here, is this the right way to do this?

Upvotes: 2

Views: 614

Answers (2)

Stuart Marks
Stuart Marks

Reputation: 132460

Yes, using min() with a Comparator is the right approach to do this. However, you don't need to create your own comparator implementation ComparatorScoreDif. Instead, you can use the Comparator.comparing combinator function to generate a Comparator, given a function that derives the values to be compared.

Most examples use method references to getters on the object being compared. If Location had a getScore method, one would do this:

Location best = locations.parallelStream()
                         .min(Comparator.comparing(Location::getScore))
                         .get();

However, getScore isn't a method on Location, and it takes some additional parameters. This will require writing out a lambda expression "longhand" instead of using a method reference. The additional values can be captured from the environment:

Location best = locations.parallelStream()
                         .min(Comparator.comparingDouble(loc -> getScore(loc, colour, average)))
                         .get();

This avoids the need to write out a class to implement Comparator.

Upvotes: 4

ifloop
ifloop

Reputation: 8386

Location best = locations.parallelStream().min(new ComparatorScoreDif(colour)).get();

That will return the actual object from the optional object. it it exists. You might call .isPresent() on the optional object beforehand to check this.

Am I going in the right direction here, is this the right way to do this?

Yes it is. By calling .parallelStream() you hand over the concurrency part to the JVM (it will partition the stream into multiple substreams)and you can focus on the actual logic that has to be executed in parallel.

See OracleDocs - Parallelism for further information and some nice explainings.

Upvotes: 1

Related Questions