列表是Java语言中最常用的集合之一。有时这个列表可能很大,创建一个子列表并对其进行操作似乎是一个非常合乎逻辑的步骤。
Java 不提供从一个大列表创建 N 个子列表的帮助器,但如您所知,我们始终可以使用现有功能来实现一个子列表或使用第三方库。
在本文中,我们将看到从大列表创建子列表的 3 个选项。
输入是一个简单的 N 个数字列表:
List<Integer> numbers = IntStream.rangeClosed(1, 11100) .boxed().toList();
|
1、使用sublist()方法获取列表的一部分
- 使用sublist()方法获取列表的一部分,然后将该部分添加到结果列表中。
- 每当下一个批次小于或等于预期的batch_size时,我们就会终止迭代。这将是最终的批次条件。
- 最后,我们将剩余的内容添加到结果中,我们就完成了!
public static void option_1(){ int batch_size = 1000; List<Integer> numbers = IntStream.rangeClosed(1, 11100) .boxed().toList(); List<List<Integer>> results = new ArrayList<>(); int start = 0; while (start+(batch_size) < numbers.size()){ int end = start+(batch_size); System.out.println(end); results.add(numbers.subList(start,end)); start=end; } results.add(numbers.subList(start, numbers.size())); results.forEach(System.out::println); }
|
改进算法:
- 可以通过添加Math.min(numbers.size(), start+batch_size)来改进我们的代码位
- Math.min 条件会在两种情况下都加上尾数,即当批次中覆盖的元素总数小于总记录大小和上一批次的剩余元素总数时加 1。
public static void option_2_modified(){ int batch_size = 1000; List<Integer> numbers = IntStream.rangeClosed(1, 11100) .boxed().toList(); int recordIdx = numbers.size(); List<List<Integer>> results = new ArrayList<>(); int start = 0; while (start < recordIdx){ results.add(numbers.subList(start, Math.min(numbers.size(), start+batch_size))); start += batch_size; } results.forEach(System.out::println); }
[b]2、[/b]
|
Java 流 API
在此方案中,我们使用 Java 流 API 对元素进行分组。
我们根据分区大小和原子整数索引提供分组逻辑。
因此,如果分区大小为 10,那么 0 -> 9 个元素将被分组,因为所有这些元素的除法结果都是 0。public static void option_2(){ int batch_size = 1000; List<Integer> numbers = IntStream.rangeClosed(1, 11100) .boxed().toList(); AtomicInteger counter = new AtomicInteger(); Collection<List<Integer>> result = numbers.stream() .collect(Collectors.groupingBy(a -> counter.getAndIncrement() / batch_size)) .values(); result.forEach(System.out::println); }
|
3、Google Guava Library
我们还可以使用辅助方法来简化我们的生活。如果我们可以自由使用第三方库,如 google guava 或 apache commons,我们就可以利用这些库提供的辅助方法。
Google Guava 有一个 Lists 实用程序类,它提供了一个分区辅助方法,可按批处理大小对列表进行分区
public static void option_3(){ int batch_size = 1000; List<Integer> numbers = IntStream.rangeClosed(1, 11100) .boxed().toList(); List<List<Integer>> partition = Lists.partition(numbers, batch_size); partition.forEach(System.out::println); }
|
4、Apache Commons Collection API
Apache Commons Collection API 有一个 ListUtils 类,它提供了一个分区辅助方法,可按批量大小对列表进行分区。
public static void option_3(){ int batch_size = 1000; List<Integer> numbers = IntStream.rangeClosed(1, 11100) .boxed().toList(); List<List<Integer>> partition = ListUtils.partition(numbers, batch_size); partition.forEach(System.out::println); }
|