如何根据项目属性的总和对集合进行分区,直至达到给定的限制?

如何根据集合中每个项目的一个字段求和,将集合分块为 N 个块,直至达到给定的最大值?


例如,给定以下内容:


class FileObject { public long sizeInBytes; }

Collection<FileObject> files;

long MAX_SIZE_THRESHOLD = 1024 * 1024 * 100; // 100 MB

我想将项转换为具有最少数量的内部集合的项,并满足谓词,即对于每个集合,每个元素的总和小于 。Collection<Collection<FileObject>>sizeInBytesMAX_SIZE_THRESHOLD


进一步说明,除了上述要求之外,如果扩展为包含时间戳,我还想按年,月和日对结果进行分区。FileObject


例如


class FileObject { public long sizeInBytes; public long modifiedDate; }

我希望最终结果如下所示:


Map<Integer, Map<Integer, Map<Integer, Collection<FileObject>>>>

其中映射中的键是:年、月和日(对应于 的 ),并且集合包含该年、月、日内的所有文件,并且每个文件的大小英寸之和小于 。FileObjectmodifiedDateMAX_SIZE_THRESHOLD


是否可以在避免循环和使用使用 Stream API 或其他可用的函数构造的同时完成这两个操作?两者都可以在一个语句中完成吗?


慕丝7291255
浏览 73回答 1
1回答

天涯尽头无女友

您可以在流交易中尝试。下面是示例代码:StreamEx.collapse(...)final long MAX_SIZE_THRESHOLD = 12; // only for test purpose.// create the sample file objects with random size for test.Collection<FileObject> files =&nbsp; &nbsp; new Random().longs(0, 1000).limit(50).mapToObj(n -> new FileObject(n % 15, n))&nbsp; &nbsp; .collect(Collectors.toList());// here is the final solution you can tryfinal MutableLong remaining = MutableLong.of(MAX_SIZE_THRESHOLD);List<List<FileObject>> result = StreamEx.of(files).collapse((a, b) -> {&nbsp; if (b.sizeInBytes <= remaining.value() - a.sizeInBytes) {&nbsp; &nbsp; remaining.subtract(a.sizeInBytes);&nbsp; &nbsp; return true;&nbsp; } else {&nbsp; &nbsp; remaining.setValue(MAX_SIZE_THRESHOLD);&nbsp; &nbsp; return false;&nbsp; }}, Collectors.toList()).toList();result.forEach(System.out::println);以下是您问题的第2部分嵌套的解决方案:groupingBy// import static java.util.stream.Collectors.*Map<Integer, Map<Integer, Map<Integer, List<FileObject>>>> result2 = files.stream()&nbsp; &nbsp; .filter(f -> f.sizeInBytes < MAX_SIZE_THRESHOLD)&nbsp; &nbsp; .collect(groupingBy(f -> f.getYear(),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupingBy(f -> f.getMonth(),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupingBy(f -> f.getDay(), toList()))));result2.entrySet().forEach(System.out::println);最后,这是我用来测试的:FileObjectstatic class FileObject {&nbsp; public long sizeInBytes;&nbsp; public long modifiedDate;&nbsp; public FileObject(long sizeInBytes, long modifiedDate) {&nbsp; &nbsp; this.sizeInBytes = sizeInBytes;&nbsp; &nbsp; this.modifiedDate = modifiedDate;&nbsp; }&nbsp; public int getYear() {&nbsp; &nbsp; return (int) modifiedDate / 100; // only for test purpose&nbsp; }&nbsp; public int getMonth() {&nbsp; &nbsp; return (int) (modifiedDate % 100) / 10; // only for test purpose&nbsp; }&nbsp; public int getDay() {&nbsp; &nbsp; return (int) modifiedDate % 10; // only for test purpose&nbsp; }&nbsp; @Override&nbsp; public String toString() {&nbsp; &nbsp; return sizeInBytes + "-" + modifiedDate;&nbsp; }}根据评论更新:您将需要 .Collectors.collectAndThenFunction<List<FileObject>, List<List<FileObject>>> finisher = fileObjs -> {&nbsp; MutableLong remaining2 = MutableLong.of(MAX_SIZE_THRESHOLD);&nbsp; return StreamEx.of(fileObjs).collapse((a, b) -> {&nbsp; &nbsp; if (b.sizeInBytes <= remaining2.value() - a.sizeInBytes) {&nbsp; &nbsp; &nbsp; remaining2.subtract(a.sizeInBytes);&nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; remaining2.setValue(MAX_SIZE_THRESHOLD);&nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; }&nbsp; }, toList()).toList();};Map<Integer, Map<Integer, Map<Integer, List<List<FileObject>>>>> result4 = files.stream()&nbsp; &nbsp; .collect(groupingBy(f -> f.getYear(),&nbsp; &nbsp; &nbsp; &nbsp; groupingBy(f -> f.getMonth(),&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupingBy(f -> f.getDay(), collectingAndThen(toList(), finisher)))));结果类型应为 ,而不是 。Map<Integer, Map<Integer, Map<Integer, List<List<FileObject>>>>>Map<Integer, Map<Integer, Map<Integer, List<FileObject>>>>顺便说一句,如果你不想写函数(我不:-)),试试我的库:算盘-Util:finisherFunction<List<FileObject>, List<List<FileObject>>> finisher2 = fileObjs -> Seq.of(fileObjs)&nbsp; &nbsp; .split(MutableLong.of(0), (f, sizeSum) -> sizeSum.addAndGet(f.sizeInBytes) <= MAX_SIZE_THRESHOLD,&nbsp; &nbsp; &nbsp; &nbsp; sizeSum -> sizeSum.setValue(0));// import static com.landawn.abacus.util.stream.Collectors.MoreCollectors.*;StreamEx.of(files)&nbsp; &nbsp; .toMap(f -> f.getYear(),&nbsp; &nbsp; &nbsp; &nbsp; groupingBy(f -> f.getMonth(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; groupingBy(f -> f.getDay(), collectingAndThen(toList(), finisher2))));
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java