如何使用 lambda 表达式将 Iterable 分成块

How to split Iterable in chunks with lambda expressions

我有 Iterable<CSVRecord> = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in)(阿帕奇公地) 记录 > 10.000.000.000 行。以前我有一个带计数器的循环,在每 x 行之后我正在处理数据。现在我尝试用 Java 8 个 lambda 表达式实现类似的效果。

到目前为止我想出了这个,但是它耗尽了内存,因为我无法找到如何在 subList

中拆分它的正确方法
  Iterable<List<?>> params = new ArrayList<>(StreamSupport
                .stream(records.spliterator(), true)
                .map(r -> Arrays.asList(
                        r.get("name"),
                        r.get("surname"),
                        r.get("something"),
                ))
                .collect(Collectors.toList()).subList(0, 20000));

末尾的子列表不起作用:(

我只需要一些关于如何拆分的概念证明 Iterable - 例如正确的地方放在哪里 subList?

我不确定你是否可以使用单个 lambda 表达式来完成,但你可以使用 .skip().limit():

int maxSize = 20000;
int currentOffset = 0; // Increment by maxSize each iteration    
Iterable<List<?>> params = new ArrayList<>(StreamSupport
                            .stream(records.spliterator(), true)
                            .skip(currentOffset)
                            .limit(maxSize)
                            .map(r -> Arrays.asList(
                                    r.get("name"),
                                    r.get("surname"),
                                    r.get("something"),
                            ))
                            .collect(Collectors.toList())

我认为适合您的情况的最佳解决方案是将数据转换阶段和分块分开。 对于数据转换(记录 -> 数组),您可以使用流或并行流。他们在这里闪耀。但是分块对于流来说不是一个好的场景,因为流一次可以产生一个块(通过 skip/limit)。所以你必须为每个块重新创建流。 最好使用简单循环或某些库 api(如 RC 推荐的那样)。

这没有回答分块的问题,但是...考虑购买更多内存。如果这是问题集的典型大小。 RAM 可能比持续编写内存高效程序的额外思考时间成本更便宜。

嗨,我不确定它是否看起来不错,但这是另一种处理方式。

//that can be CsvParser not List
List<Integer> collection = Arrays.asList(1, 2, 4, 5, 2, 1, 2, 4, 5);

int limit = 2;
int size =  collection.size();

long maxPartIndex =  (long) Math.ceil((double) size/ limit);

LongStream.range(0, maxPartIndex)
    .mapToObj(partIndex -> getPart(collection.spliterator(), partIndex, limit))
    .forEach(System.out::println);

.....

private static <T> List<T> getPart(Spliterator<T> stream, long index, long size) {
    return StreamSupport.stream(stream, false)
    .skip(index * size)
    .limit(size)
    .collect(Collectors.toList());
}

输出:

(1, 2) (4, 5) (2, 1) (2, 4) (5)