Java 具有已知边界的流最小值
Java Stream minimum with known bound
我有一个列表流,我想从中获取元素最少的条目。我当然可以做类似
的事情
Stream<List<T>> s = ...
s.min((e1, e2) -> e1.size() - e2.size());
但在这种情况下,我们知道最小值的下限,因为大小是非负的。这意味着当找到大小为 0 的列表时,我们实际上可以停止,而不是 运行 遍历列表的其余部分。
这可以通过 Java Streams 以一种体面的方式实现吗?
我会想象它看起来像这样,提供一个比较器和一个函数,告诉我们当前最小值何时是全局最小值:
s.boundedMin(
(e1, e2) -> e1.size() - e2.size(),
e -> e.size() == 0
)
我想不出实现它的方法。
当然我可以只使用 Iterable 并使用带有 break 语句的循环来获得它,我只是想知道流是否也可以让我到达那里。
编辑:
为了让它更清楚一点。流 可能 或 可能不 包含大小为 0 的列表。我的问题是 min() 将 运行 通过整个流,即使它已经找到了一个大小为 0 的列表(这已经是它所能得到的最小的列表)。所以,我正在寻找的是 min 的实现,它不需要扫描整个流,通过提供最小值的下限。
编辑2:
没有流的等效迭代解决方案是
List<List<T>> s = ...
List<T> min = null;
for (List<T> l : s) {
if (min == null || min.size() > l.size())
min = l;
if (min.size() == 0) {
break;
}
}
只是为了好玩:
static <T> int size(Stream<List<T>> st) {
class MinHolder implements Consumer<List<T>> {
private int min = Integer.MAX_VALUE;
public void accept(List<T> l) {
if (min > l.size()) {
min = l.size();
}
}
}
MinHolder holder = new MinHolder();
Spliterator<List<T>> sp = st.spliterator();
int elements = 0;
for (; sp.tryAdvance(holder) && holder.min > 0; ++elements) {
}
System.out.printf("took %s elements to find the min%n", elements);
return holder.min;
}
还有一些测试用例:
public static void main(String[] args) {
Stream<List<Integer>> st = Stream.of(List.of());
System.out.println(size(st));
st = Stream.empty();
System.out.println(size(st));
st = Stream.of(List.of(), List.of(1), List.of(1, 2), List.of(1, 2, 3));
System.out.println(size(st));
}
如果你不是被迫使用 Stream<List<T>>
那么就不要;这种 有条件的 中断不是 Streams 的设计目的,许多人会认为这是一种滥用。
我有一个列表流,我想从中获取元素最少的条目。我当然可以做类似
的事情Stream<List<T>> s = ...
s.min((e1, e2) -> e1.size() - e2.size());
但在这种情况下,我们知道最小值的下限,因为大小是非负的。这意味着当找到大小为 0 的列表时,我们实际上可以停止,而不是 运行 遍历列表的其余部分。 这可以通过 Java Streams 以一种体面的方式实现吗?
我会想象它看起来像这样,提供一个比较器和一个函数,告诉我们当前最小值何时是全局最小值:
s.boundedMin(
(e1, e2) -> e1.size() - e2.size(),
e -> e.size() == 0
)
我想不出实现它的方法。
当然我可以只使用 Iterable 并使用带有 break 语句的循环来获得它,我只是想知道流是否也可以让我到达那里。
编辑: 为了让它更清楚一点。流 可能 或 可能不 包含大小为 0 的列表。我的问题是 min() 将 运行 通过整个流,即使它已经找到了一个大小为 0 的列表(这已经是它所能得到的最小的列表)。所以,我正在寻找的是 min 的实现,它不需要扫描整个流,通过提供最小值的下限。
编辑2: 没有流的等效迭代解决方案是
List<List<T>> s = ...
List<T> min = null;
for (List<T> l : s) {
if (min == null || min.size() > l.size())
min = l;
if (min.size() == 0) {
break;
}
}
只是为了好玩:
static <T> int size(Stream<List<T>> st) {
class MinHolder implements Consumer<List<T>> {
private int min = Integer.MAX_VALUE;
public void accept(List<T> l) {
if (min > l.size()) {
min = l.size();
}
}
}
MinHolder holder = new MinHolder();
Spliterator<List<T>> sp = st.spliterator();
int elements = 0;
for (; sp.tryAdvance(holder) && holder.min > 0; ++elements) {
}
System.out.printf("took %s elements to find the min%n", elements);
return holder.min;
}
还有一些测试用例:
public static void main(String[] args) {
Stream<List<Integer>> st = Stream.of(List.of());
System.out.println(size(st));
st = Stream.empty();
System.out.println(size(st));
st = Stream.of(List.of(), List.of(1), List.of(1, 2), List.of(1, 2, 3));
System.out.println(size(st));
}
如果你不是被迫使用 Stream<List<T>>
那么就不要;这种 有条件的 中断不是 Streams 的设计目的,许多人会认为这是一种滥用。