Class Coordinate
properties x
and y
of type double
, and a method to compute the distance from this point to another given point:
public record Coordinate(double x, double y) {
public double distanceTo(Coordinate point) {
// implementation
}
}
I want to write a method furthestCoordinate
that determines the farthest point from the point base
in a given stream and return the base itself if the stream is empty. I have written an Comparator
which compares Coordinate
Objects with the base
, but it throws an exception when given an empty stream:
static Comparator<Coordinate> WayPointComparator = new Comparator<>() {
@Override
public int compare(Coordinate o1, Coordinate o2) {
return Double.compare(o1.distanceTo(basePoint),o2.distanceTo(basePoint));
}
};
public static Coordinate furthestCoordinate(Stream<Coordinate> coordinateStream, Coordinate base) {
basePoint = base; // safes the base to be accessible for the Comparator
return coordinateStream.max(WayPointComparator).get();
}
How can I use an accumulator, which gets updated whenever the next Coordinate
in the Stream is farther away and returns 'base' itself if the Stream is empty?
CodePudding user response:
You can use Java 8 method Comparator.comparingDouble()
to define a comparator based on the method distanceTo()
of your Coordinate
class.
And to base
coordinate if the given stream was empty, apply Optional.orElse()
on the Optional
returned by Stream.max()
operation.
public static Coordinate furthestCoordinate(Stream<Coordinate> coordinateStream,
Coordinate base) {
return coordinateStream
.max(Comparator.comparingDouble(base::distanceTo)) // produces Optional<Coordinate>
.orElse(base);
}
CodePudding user response:
Here is one way to do it. I am using the JDK classes Math
and Point2D.Double
Some data
List<Point2D> list = new ArrayList<>(
List.of(
new Point2D.Double(2.0, 10.0),
new Point2D.Double(5.0, 6.0),
new Point2D.Double(4.0, 9.3)));
Point2D basePoint = new Point2D.Double(0., 0.);
A defined comparator.
Comparator<Point2D> distanceComp = Comparator
.comparingDouble(point -> Math.hypot(basePoint.getX() - point.getX(),
basePoint.getY() - point.getY()));
And the stream.
list.stream().collect(Collectors.maxBy(distanceComp))
.ifPresentOrElse(point->System.out.println("Max point is " point),
() -> System.out.println("Empty stream"));
prints
Max point is Point2D.Double[2.0, 10.0]
Collectors.maxBy returns an Optional<Point2D.Double>
. So using IfPresentOrElse can handle the answer or report an empty stream.
If you prefer to use your own classes and methods for the point and distance then the above should still work just fine.
Here is a function to get a comparator for a specific basePoint
.
static Function<Point2D, Comparator<Point2D>> getComparator = base -> Comparator
.comparingDouble(point -> Math.hypot(base.getX() - point.getX(),
base.getY() - point.getY()));
You can then call your method with a stream
and the basePoint
.
public static Point2D furthestCoordinate(Stream<Point2D> coordinateStream,
Point2D basePoint) {
return coordinateStream
.collect(Collectors.maxBy(getComparator.apply(basePoint)))
.orElse(basePoint);
}
Note: In this case I returned the basePoint
for an empty stream. But any point could be a valid answer. You may want to just return the optional
and the use ifPresent
or someother supported method to best determine how to handle an empty stream.