使用 lambda 的 List<> 的 Java8 子列表

问题描述 投票:0回答:4

我有一个问题,我认为它对于流和/或 lambda 来说是完美的。另一方面,我不想让这个变得过于复杂,但由于将在许多变体中使用这种特定的技术(在子列表上运行函数),我想知道一些关于如何从一开始就正确使用它的想法。

我有一个

List<Product> productList

我希望能够迭代

productList
中的所有子列表。例如,所有大小=30 的子列表。然后应该将该子列表用作函数的参数。

这是我当前的、天真的解决方案:

List<Product> products=...
// This example uses sublists of size 30
for (int i = 0; i < products.size() - 29; i++) {
    // sublist start index is inclusive, but end index is exclusive
    List<Product> sublist = products.subList(i, i + 30);
    Double res = calc(sublist);
}

// an example of a function would be moving average

如何使用 lambda 来实现这一点?

编辑 我试图想出一个最简单的例子来说明这个问题。经过一些评论后,我意识到一个完美的例子是计算移动平均线。第一个 MAVG 在子列表 [0..29] 上计算,第二个在 [1..30] 上计算,第三个在 [2..31] 上计算,依此类推。

java list lambda java-8 java-stream
4个回答
7
投票

除非我遗漏了一些明显的东西......

IntStream.range(0, products.size() - 29)
            .mapToObj(i -> products.subList(i, i + 30))
            .map(list -> calc(list))
            .forEach... // or any other terminal op

如果您想对这些子列表运行多个函数,例如:

double result = calc(sublist)
log(sublist) // void
double res = diffCalc(sublist)

您可能不再使用通常的 for 循环。

a

map
操作对子列表执行单个操作,可以使其在流中执行更多操作,但这在我看来真的很难看。


6
投票

如果您不介意使用第三方库,

StreamEx
中有一个方法subLists可以完全满足您的需求:

List<Product> products = ...
Stream<List<Product>> lists = StreamEx.ofSubLists(products, 30, 1);

1
投票

我认为使用 lambda 代码可能不太清晰。也许普通的旧if比现代的lambda更好?

    int sizeSubList = 30;

    for (int i = 0; i < products.size(); i++)
        calc(products.subList(i, Math.min(i + sizeSubList, products.size())));

0
投票

JEP 461:Stream Gatherers Java 22 预览语言功能可用于实现所需的结果:

List<Double> results = productList.stream()
        .gather(Gatherers.windowSliding(30))
        .map(sublist -> calc(sublist))
        .toList();

这使用新的

Stream.gather
方法和新的内置
Gatherers.windowSliding
收集器将地图的条目集从
Stream<Entry>
转换为成对
Stream<List<Entry>>
。然后使用现有的
String[]
 方法将每个二元素列表转换为二元素 
Stream.map

演练

使用子列表大小 3 和对子列表中的值进行平均的函数进行流演练:

[
  Product(value = 0),
  Product(value = 1),
  Product(value = 2),
  Product(value = 3),
  Product(value = 4)
]

->

[
  [Product(value = 0), Product(value = 1), Product(value = 2)],
  [Product(value = 1), Product(value = 2), Product(value = 3)],
  [Product(value = 2), Product(value = 3), Product(value = 4)]
]

->

[1, 2, 3]

Java文档

Gatherer

将输入元素流转换为输出元素流的中间操作,可以选择在到达上游末尾时应用最终操作。 […]

[…]

聚集操作的例子有很多,包括但不限于:将元素分组(窗口函数);对连续相似的元素进行去重;增量累加功能(前缀扫描);增量重新排序功能等。类

Gatherers
提供了常见收集操作的实现。

Stream.gather

返回一个流,其中包含将给定收集器应用于该流的元素的结果。

Gatherers.windowSliding

返回一个 Gatherer,它将元素收集到给定大小的窗口(遇到有序的元素组)中,其中每个后续窗口都包含前一个窗口的所有元素(除了最近的元素之外),并在流中添加下一个元素。 […]

示例:

// will contain: [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8]]
List<List<Integer>> windows2 =
    Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowSliding(2)).toList();

// will contain: [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7], [3, 4, 5, 6, 7, 8]]
List<List<Integer>> windows6 =
    Stream.of(1,2,3,4,5,6,7,8).gather(Gatherers.windowSliding(6)).toList();
© www.soinside.com 2019 - 2024. All rights reserved.