Title is sort of confusing but I'm not sure how to explain my problem in a simple sentence.
I have a homework task to group an arraylist of rectangles by length (same as perimeter in this case) using streams and collectors and to calculate minimum width for each group. I have tried the following:
public static Map<Double, Double> groupIndenticalPerimeterWidth(ArrayList<Rectangle> rectangles){
return rectangles.stream().collect(Collectors.groupingBy(Rectangle::getLength, Collectors.minBy((rectangle1, rectangle2) -> Double.compare(rectangle1.getWidth(), rectangle2.getWidth()))));
}
which gets me a Map<Double, Optional<Rectangle>> and I can't figure out how to get the width of minimum rectangle in the second arguement of Collectors.groupingBy instead of Optional<Rectangle>
Any help appreciated
CodePudding user response:
group an arraylist of rectangles by
length(same as perimeter in this case) using streams and collectors and to calculate minimumwidthfor each group.
As you've noticed, collector minBy() produces Optional<Rectangle>.
To get double property from the optional result, you can use collector collectingAndThen(). It expects a collector (minBy() in this case) as the first argument, and a function that transforms the result produced by the collector as the second argument.
public static Map<Double, Double> groupIndenticalPerimeterWidth(ArrayList<Rectangle> rectangles){
return rectangles.stream()
.collect(Collectors.groupingBy(
Rectangle::getPerimeter,
Collectors.collectingAndThen(
Collectors.minBy(Comparator.comparingDouble(Rectangle::getWidth)),
result -> result.map(Rectangle::getWidth).orElseThrow() // `map` transforms Optional<Rectangle> into Optional<Double> and `orElseThrow` extracts the value from the optional
)
));
}
Dummy Rectangle class:
public static class Rectangle {
private double height;
private double width;
public double getPerimeter() {
return 2 * (height width);
}
// getters
}
Sidenote: it's highly advisable to use Java 8 static methods when you need to define a compactor.
CodePudding user response:
Instead of groupingBy with the necessity to extract an Optional you can do it easier with toMap with a merge function:
public static Map<Double, Double> groupIndenticalPerimeterWidth(List<Rectangle> rectangles) {
return rectangles.stream()
.collect(Collectors.toMap(
Rectangle::getPerimeter, Rectangle::getWidth, Math::min));
}
