如何根据指定分片数创建近似等长的对象子列表?
问题描述
我有一个包含N个对象的ArrayList,对象结构如下:
[ { "firstName": "Todd", "lastName": "Jones" }, { "firstName": "Mike", "lastName": "Johnson" }, { "firstName": "Tina", "lastName": "Jones" }, { "firstName": "Tommy", "lastName": "Wiseau" }, .... ]
我需要根据传入的当前分片索引(chunkIndex)和总分片数(numOfChunks),把列表拆成近似等份的子任务。现在写的逻辑没处理无法整除的情况,导致索引出错,请问怎么确保subList的索引始终正确?
示例场景:9个姓名对象,拆成2个近似等长数组,取第1片。
当前有问题的逻辑代码:
final int namesCount = names.size(); final int namesDividedCount = namesCount / numOfChunks; int startIndex, endIndex; if (chunkIndex == 1) { startIndex = 0; endIndex = namesDividedCount; } else if (chunkIndex == numOfChunks) { startIndex = namesCount - namesDividedCount; endIndex = namesCount; } else { startIndex = ((chunkIndex - 1) * namesDividedCount) + 1; endIndex = chunkIndex * namesDividedCount; } return names.subList(startIndex, endIndex);
修正方案
原有逻辑的核心问题有两个:
- 没处理无法整除时的余数:比如9个元素分2片,按原有逻辑会分成4和4,直接漏掉1个元素
- 中间分片的
startIndex多了+1,导致分片之间出现元素遗漏
下面提供两种可靠的实现方式,都能解决整除/非整除场景的索引问题:
方式一:余数优先分配给前N个分片
这种方式会让前面的分片比后面的多1个元素(当无法整除时),比如9分2片,结果是5、4,更符合"近似等长"的直觉:
final int namesCount = names.size(); final int baseSize = namesCount / numOfChunks; final int remainder = namesCount % numOfChunks; // 计算当前分片的起始索引 int startIndex = (chunkIndex - 1) * baseSize + Math.min(chunkIndex - 1, remainder); // 计算当前分片的结束索引 int endIndex = startIndex + baseSize + (chunkIndex <= remainder ? 1 : 0); // 兜底处理,防止极端情况索引越界(逻辑上不会触发,但加一层更安全) startIndex = Math.max(0, startIndex); endIndex = Math.min(namesCount, endIndex); return names.subList(startIndex, endIndex);
验证示例:9个元素,numOfChunks=2,chunkIndex=1
- baseSize=4,remainder=1
- startIndex=(1-1)*4 + min(0,1) = 0
- endIndex=0+4 + (1<=1?1:0) =5
- 最终取0到5的子列表,共5个元素,符合预期
方式二:整数除法自动分配余数
这种写法更简洁,余数会自动分配给后面的分片,比如9分2片,结果是4、5:
final int namesCount = names.size(); int startIndex = (namesCount * (chunkIndex - 1)) / numOfChunks; int endIndex = (namesCount * chunkIndex) / numOfChunks; return names.subList(startIndex, endIndex);
验证示例:9个元素,numOfChunks=2,chunkIndex=1
- startIndex=(90)/2=0,endIndex=(91)/2=4 → 取0-4的子列表,共4个元素
- chunkIndex=2时,startIndex=(9*1)/2=4,endIndex=9 → 取4-9的子列表,共5个元素
两种方式都能保证所有元素被覆盖,不会出现遗漏或索引越界的问题,根据你的实际需求选择即可。
内容的提问来源于stack exchange,提问作者spaceghost
相关产品推荐
相关产品推荐

