【发布时间】:2017-02-03 10:45:11
【问题描述】:
我正在寻找一种简洁的方法来查找一组属性值,这些属性值在给定的对象流中是最小的或最大的。
例如:
class Dimensions {
final int startX, startY, endX, endY; //Set by constructor
}
/**
* For the given dimensions, looks where the dimensions intersect.
* These coordinates define the sub-array, which is applied to the given function.
*
* @return the value returned by applying the sub-array in the given dimensions to the given function
*/
<S, T> T performOnIntersections(Function<S, T> function, S[][] inputArray, Dimensions...dimensions){
int maxStartX = Arrays.stream(dimensions).max(Comparator.comparingInt(d -> d.startX)).get().startX;
int maxStartY = Arrays.stream(dimensions).max(Comparator.comparingInt(d -> d.startY)).get().startY;
int minEndX = Arrays.stream(dimensions).min(Comparator.comparingInt(d -> d.endX)).get().endX;
int minEndY = Arrays.stream(dimensions).min(Comparator.comparingInt(d -> d.endY)).get().endY;
return applyInBetween(inputArray, function, maxStartX, maxStartY, minEndX, minEndY);
}
这是非常多余的,因为我必须为我需要的每个最小/最大属性创建一个新流。
在我的用例中,类似的方法是指数成本递归算法的一部分,因此拥有一个仅打开一次流的并发解决方案会很棒。更好的是一种解决方案,它可以在现有流上运行而不会终止(但我怀疑这是可能的)。
你知道如何改进它吗?
编辑:我忘了提,Dimension 是不可变的,这在使用 Supplier 时是相关的。
编辑 2: 使用 lambda 表达式在流上调用 collect() 而不是创建 DimensionsMinMaxCollector 的实例具有最佳的运行时性能。 jessepeng 首先提到它,所以我将他的帖子标记为解决方案。我现在的实现是:
return Arrays.stream(dimensions)
.collect(() -> new int[4], (array, dimension) -> {
array[0] = Math.max(array[0], dimension.startX);
array[1] = Math.min(array[1], dimension.endX);
array[2] = Math.max(array[2], dimension.startY);
array[3] = Math.min(array[3], dimension.endY);
}, (a, b) -> {
a[0] = Math.max(a[0], b[0]);
a[1] = Math.min(a[1], b[1]);
a[2] = Math.max(a[2], b[2]);
a[3] = Math.min(a[3], b[3]);
});
【问题讨论】:
-
我认为使用 Streams 是不可能的,因为它们只能使用一次。要一次执行多项操作,请使用老式的 for-each 循环。
-
可能是
dimArray = Arrays.asList(dimensions);等其他选项,然后尝试使用Collections.max(dimArray, Comparator.comparingInt(d -> d.startX))等?
标签: java lambda java-stream