英文:
Minimum of a Stream of DoubleProperty as a DoubleProperty
问题
有没有办法获取Stream
(或List
,Set
,ArrayList
)中DoubleProperty
的最小值并将其写入DoubleProperty
变量中?
特别是,我有一个包含JavaFX矩形的ArrayList
,我想将这些矩形的xProperty()
的最小值写入一个DoubleProperty
变量中。我尝试了以下代码
import javafx.beans.property.DoubleProperty;
import javafx.scene.shape.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;
public class Test4 {
public static void main(String[] args) {
Random rnd = new Random();
List<Rectangle> rectangles = new ArrayList<>();
for (int i = 0; i < 50; i++) {
rectangles.add(new Rectangle(rnd.nextDouble(), rnd.nextDouble(), 100, 100));
}
Optional<DoubleProperty> minX = rectangles.stream().map(Rectangle::xProperty).min();
}
}
然而,这行代码Stream<DoubleProperty> minX = rectangles.stream().map(Rectangle::xProperty).min();
引发了以下错误:
'min(java.util.Comparator<? super javafx.beans.property.DoubleProperty>)' in 'java.util.stream.Stream' cannot be applied to '()'
有没有办法解决这个问题?
英文:
Is there any way to fetch the minimum of a Stream
(or List
, Set
, ArrayList
) of DoubleProperty
and write it into a DoubleProperty
variable?
In particular, I have an ArrayList
of JavaFX Rectangles and I want to write the minimum of xProperty()
of these Rectangles into a DoubleProperty
variable. I tried the following code
import javafx.beans.property.DoubleProperty;
import javafx.scene.shape.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Stream;
public class Test4 {
public static void main(String[] args) {
Random rnd = new Random();
List<Rectangle> rectangles = new ArrayList<>();
for (int i = 0; i < 50; i++) {
rectangles.add(new Rectangle(rnd.nextDouble(), rnd.nextDouble(), 100, 100));
}
Optional<DoubleProperty> minX = rectangles.stream().map(Rectangle::xProperty).min();
}
}
However, the line Stream<DoubleProperty> minX = rectangles.stream().map(Rectangle::xProperty).min();
raises the following error:
'min(java.util.Comparator? super javafx.beans.property.DoubleProperty>)' in 'java.util.stream.Stream' cannot be applied to '()'
Is there anyway to tackle this problem?
答案1
得分: 3
您遇到的具体错误是因为Stream.min()
需要一个参数来指定如何对流中的元素排序。在这种情况下,您希望按其包装的double
值对DoubleProperty
进行排序,因此可以这样做:
Optional<DoubleProperty> minX = rectangles.stream()
.map(Rectangle::xProperty())
.min(Comparator.comparing(Double::getValue));
(获取x属性的流,然后选择具有最小值的属性)
或者等效地:
Optional<DoubleProperty> minX = rectangles.stream()
.min(Comparator.comparing(Rectangle::getX))
.map(Rectangle::xProperty());
(选择具有最小x值的矩形,然后获取其x属性)。
但是请注意,这些可能不会实现您想要的功能。最小的x值将在执行该代码的时间找到,并且您将获得包装该值的DoubleProperty
。如果将另一个具有较小x
值的矩形添加到列表中,您仍然引用原始的DoubleProperty
;类似地,如果与接收的属性相对应的矩形的x值发生更改,以至于不再是最小值,则您的属性将不再表示最小值。
我假设您希望的是一个可以被观察的值(您可以向其注册监听器),并且如果列表发生更改或列表中的任何矩形的x
属性发生更改,它将更新。
您可以创建一个可以实现此功能的绑定。您需要创建一个带有提取器的可观察列表,以便可以在列表更改或列表中的任何矩形的xProperty()
更改时使绑定失效。
然后使用 Bindings.createDoubleBinding()
,并使用一个计算最小值并绑定到列表的函数:
public static void main(String[] args) {
Random rnd = new Random();
// 创建带有提取器的列表:
ObservableList<Rectangle> rectangles =
FXCollections.observableArrayList(rect -> new Observable[] { rect.xProperty()});
DoubleBinding minX = Bindings.createDoubleBinding(
() -> rectangles.stream()
.mapToDouble(Rectangle::getX)
.min()
.orElse(Double.POSITIVE_INFINITY),
rectangles
);
minX.addListener((obs, oldMin, newMin) -> System.out.println("Min X changed from " + oldMin + " to " + newMin));
for (int i = 0; i < 50; i++) {
rectangles.add(new Rectangle(rnd.nextDouble(), rnd.nextDouble(), 100, 100));
}
}
DoubleBinding
可能适用于您需要的任何功能(类似于 DoubleProperty
,它实现了 ObservableDoubleValue
,提供了您可能需要的几乎所有API)。如果您确切地需要一个属性,只需执行以下操作:
DoubleProperty minXProperty = new SimpleDoubleProperty();
minXProperty.bind(minX);
英文:
The specific error you get is because Stream.min()
requires a parameter specifying how to order the elements of the stream. In this case, you want to order the DoubleProperty
by its wrapped double
value, so you can do
Optional<DoubleProperty> minX = rectangles.stream()
.map(Rectangle::xProperty)
.min(Comparator.comparing(Double::getValue));
(get a stream of the x properties, and then choose the one with the minimum value)
Equivalently:
Optional<DoubleProperty> minX = rectangles.stream()
.min(Comparator.comparing(Rectangle::getX))
.map(Rectangle::xProperty);
(choose the rectangle with the minimum x, and then get its x property).
Note, however, that these probably don't do what you want. The minimum x value will be found at the time that code is executed, and you get the DoubleProperty
that wraps that value. If another rectangle with a smaller x
value is added to the list, you still have a reference to the original DoubleProperty
; similarly if the x-value of the rectangle corresponding to the property you received is changed so it is no longer the minimum, then your property will no longer represent the minimum value.
I'm assuming that what you want is a value which can be observed (you can register listeners with it) and which updates if either the list changes or if the x
property of any rectangles in the list change.
You can create a binding that does this. You need to create an observable list with an extractor so that the binding can be invalidated when either the list changes, or the xProperty()
of any of the rectangles in the list change.
Then use Bindings.createDoubleBinding()
with a function that computes the minimum value and binds to the list:
public static void main(String[] args) {
Random rnd = new Random();
// create list with an extractor:
ObservableList<Rectangle> rectangles =
FXCollections.observableArrayList(rect -> new Observable[] { rect.xProperty()});
DoubleBinding minX = Bindings.createDoubleBinding(
() -> rectangles.stream()
.mapToDouble(Rectangle::getX)
.min()
.orElse(Double.POSITIVE_INFINITY),
rectangles
);
minX.addListener((obs, oldMin, newMin) -> System.out.println("Min X changed from "+oldMin+" to "+newMin));
for (int i = 0; i < 50; i++) {
rectangles.add(new Rectangle(rnd.nextDouble(), rnd.nextDouble(), 100, 100));
}
}
The DoubleBinding
will probably work for anything you need (like a DoubleProperty
it implements ObservableDoubleValue
, which provides almost all the API you are likely to need). It you specifically need a property, just do
DoubleProperty minXProperty = new SimpleDoubleProperty();
minXProperty.bind(minX);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论