8. Разделить список на подсписки фиксированного размера
Условие задачи:
Дан список элементов и размер группы size.
Необходимо разделить исходный список на последовательные подсписки размером не более size.
Если количество элементов не делится на size без остатка, последний подсписок должен содержать оставшиеся элементы.
Например:
Список: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
size = 3
Результат:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Спойлеры к решению
Подсказки
size.💡 Начало очередного подсписка — текущий индекс
i.💡 Конец можно вычислить как
Math.min(i + size, list.size()).💡 Необходимо проверить, что
size > 0.💡
subList() возвращает представление части исходного списка, а не независимую копию.Решение
Простой вариант через цикл:
public static <T> List<List<T>> partition(List<T> list, int size) {
if (size <= 0) {
throw new IllegalArgumentException("size must be greater than 0");
}
List<List<T>> result = new ArrayList<>();
for (int i = 0; i < list.size(); i += size) {
int toIndex = Math.min(i + size, list.size());
result.add(new ArrayList<>(list.subList(i, toIndex)));
}
return result;
}
Например:
List<Integer> numbers = List.of(
1, 2, 3, 4, 5,
6, 7, 8, 9, 10
);
System.out.println(partition(numbers, 3));
Результат:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
Цикл двигается по исходному списку с шагом:
i += size
Правая граница очередной группы вычисляется так:
Math.min(i + size, list.size())
Поэтому для последней неполной группы индекс никогда не выйдет за границы списка.
new ArrayList<>(...) используется намеренно:
new ArrayList<>(list.subList(i, toIndex))
subList() сам по себе возвращает представление исходного списка. Если нужны независимые подсписки, их лучше скопировать.
Вариант через Stream API:
public static <T> List<List<T>> partitionStream(List<T> list, int size) {
if (size <= 0) {
throw new IllegalArgumentException("size must be greater than 0");
}
int groups = (list.size() + size - 1) / size;
return IntStream.range(0, groups)
.mapToObj(i -> {
int fromIndex = i * size;
int toIndex = Math.min(fromIndex + size, list.size());
return new ArrayList<>(
list.subList(fromIndex, toIndex)
);
})
.collect(Collectors.toList());
}
Для обычного списка с быстрым доступом по индексам временная сложность — O(n), дополнительная память — O(n) для результирующих подсписков.