使用 Java 流到 assemble 列表

Use Java Streams to assemble a list

我有一个名为“文件”的实体,具有以下属性:

public class File {
    private int id;
    private String proposal;
    private String hash;
    private String path;
    private LocalDateTime createdAt;
    private LocalDateTime finishedAt;
    private int size;
    private boolean processed;
}

我需要组织一个队列,其中的文件将上传到特定服务。对于每次提交,我可以发送尽可能多的文件,只要它们的大小总和不超过 100mb。此外,我必须遵守每个文件允许的最大日期(在本例中涉及 finishedAt 属性)。

我已经设法对我的列表进行排序。换句话说,我能够确定先上传哪些文件:

files.sort(Comparator.comparing(File::getFinishedAt));
files.stream().forEach(file -> System.out.println(file.getId()));

现在我想要 assemble 一个数组,其中包含每次提交时将对哪些文件进行排序的列表。类似的东西:

[[1, 4, 7], [8, 2], [6, 3], [5]]

上述数组的每个“子集”都涉及一个上传。上面是我的文件的 ID。所以我想要的是我的程序 return 一个数组数组,其中每个集合包含尽可能多的文件(只要它们的总和不超过 100mb)。由于每条记录都有截止日期 (finishedAt),因此它们也需要按顺序排列。

最合适的方法是什么?我试图了解 Java 中的 Streams,但我最多只能根据日期对列表进行排序。使用 Streams 可以达到我显示的结果吗?实现这些目标最合适的方法是什么?

非常感谢!

Stream API 有其自身的局限性,可能不适用于给定任务中发生的有状态操作:此处应收集子列表(或需要增加适当的索引)直到大小限制满足,然后计算应该从最后处理的索引计算。也就是说,有两个状态参数:一个总和和一对 first/last 索引来定义一个子列表。

因此,可能会建议基于循环的旧解决方案。

更新

添加了返回 int[][] 数组的 ID。

static int[][] groupFiles(List<File> files) {
    files.sort(Comparator.comparing(File::getFinishedAt));
    
    List<int[]> result = new ArrayList<>();
    
    for (int i = 0, n = files.size(); i < n; i++) {
        int sum = 0;
        int j = i;
        for (; j < n && sum + files.get(j).size <= 100; sum += files.get(j++).size);
    
        System.out.println("total size=" + sum + "; sublist: [" + i + ", " + j + "]");
        
        List<File> sublist = files.subList(i, j);
        
        sublist.forEach(s -> System.out.println("\t" + s));
        i = --j;
        
        sendFiles(sublist);
        result.add(sublist.stream().mapToInt(File::getId).toArray());
    }
    return result.toArray(new int[0][]);
}

测试:

List<File> files = Arrays.asList(
    new File(1, "f1", LocalDateTime.of(2021, 12, 20, 20, 00), 55),
    new File(2, "f2", LocalDateTime.of(2021, 12, 20, 19, 45), 20),
    new File(3, "f3", LocalDateTime.of(2021, 12, 20, 19, 30), 40),
    new File(4, "f4", LocalDateTime.of(2021, 12, 20, 19, 50), 45),
    new File(5, "f5", LocalDateTime.of(2021, 12, 20, 20, 10), 35)
);
        
System.out.println(Arrays.deepToString(groupFiles(files)));

输出:

total size=60; sublist: [0, 2]
    File: id=3; path=f3; finishedAt=2021-12-20T19:30; size=40
    File: id=2; path=f2; finishedAt=2021-12-20T19:45; size=20
total size=100; sublist: [2, 4]
    File: id=4; path=f4; finishedAt=2021-12-20T19:50; size=45
    File: id=1; path=f1; finishedAt=2021-12-20T20:00; size=55
total size=35; sublist: [4, 5]
    File: id=5; path=f5; finishedAt=2021-12-20T20:10; size=35
[[3, 2], [4, 1], [5]]