Как разделить массив значений на заданное количество групп
Например, есть вот такой код
final List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
final int chunkSize = 3;
final AtomicInteger counter = new AtomicInteger();
final Collection<List<Integer>> result = numbers.stream()
.collect(Collectors.groupingBy(it -> counter.getAndIncrement() / chunkSize))
.values();
System.out.println(result);
или такой
List<String> originalList = Arrays.asList("1", "2", "3",
"4", "5", "6", "7", "8", "9", "10", "11");
int partitionSize = 3;
List<List<String>> partitions = new LinkedList<>();
for (int i = 0; i < originalList.size(); i += partitionSize) {
int min = Math.min(i + partitionSize, originalList.size());
partitions.add(originalList.subList(i, min ));
}
System.out.println(partitions);
Но в них происходит создание отдельных массивов в которые помещается заданное количество элементов.
Но задача состоит в том, чтобы поделить массив таким образом (массив имеет N-длину), чтобы можно было поместить в него равномерно количество элементов из оригинального массива.
Например, есть массив файлов из 16 файлов, нужно разбить оригинальный массив на 3 группы и нужно из этого массива произвести копирование некоторого количества файлов в эти 3 группы равномерно. В первой группе например, будет 5 элементов, во второй 5 элементов, а в 3-й 6 элементов ....
File[] files = sourceFolder.listFiles();
File[] filesFirstArr = divideArray(files, ?, ?);
public static File[] divideArray(File[] filesOrigin, int posCopySource , int sizeArrayFiles){
File[] filesPart = new File[sizeArrayFiles];
System.arraycopy(filesOrigin, posCopySource, filesPart, 0, sizeArrayFiles);
return filesPart;
}
Вызов этого метода будет происходить в цикле, например, так
File[] files = sourceFolder.listFiles();
for(int i = 0; i < sourceFolder.length(); i += partitionSize){
...
}
Не могу понять, как найти вычислить величину позиции копирования элементов (начальную, для каждой новой группы элементов) и не могу понять как вычислить очередной размер массива, очередной группы элементов)
У кого есть идеи, как это сделать ?
Ответы (2 шт):
как вычислить очередной размер массива, очередной группы элементов
int partitionSize = files.length / numberOfChunks;
int rest = files.length % numberOfChunks;
// Принимаем решение о том, что делать с неполным остатком
boolean includeRest = rest < partitionSize / 2;
// уменьшаем количество итераций на одну, если нужно
int bound = sequence.length - (includeRest ? partitionSize : 0);
for(int i = 0; i < bound; i += partitionSize){
boolean isLastChunk = (i + partitionSize) >= bound;
File[] chunk = Arrays.copyOfRange(files, i,
(isLastChunk && includeRest)
? files.length
: Math.min(files.length, i + partitionSize));
// ...
}
Обновление (основано на предложенном решении, участника форума - vp_arth )
public static void main(String[] args){
int partitionSize = 3;
FileWriteRepository fileWriteRepository = new FileWriteRepositoryImpl();
String srcFolder = "source";
File sourceFolder = fileWriteRepository.getPathDirToSource(srcFolder);
File[] files = sourceFolder.listFiles();
List<File[]> dividingFiles = runDividingFiles(files, partitionSize);
}
private static List<File[]> runDividingFiles(File[] files, int numberOfChunks){
List<File[]> resultArr = new ArrayList<>();
/*количество файлов в одном сегменте*/
int partitionSize = files.length / numberOfChunks;
/*получаем размер последнего неполного сегмента*/
int rest = files.length % numberOfChunks;
/*получаем половину одного сегмента*/
int halfOneSegment = partitionSize / 2;
/*проверяем, нужно ли включать остаток в текущий собираемый массив*/
boolean includeRest = false;
if(rest > 0 && rest <= halfOneSegment) includeRest = true;
/* уменьшаем количество итераций на одну, если нужно*/
int bound = files.length - (includeRest ? partitionSize : 0);
/*каждый цикл формируем новый массив файлов, который представляет собой
* один из сегментов оригинального большого массива*/
for (int i = 0; i < bound; i += partitionSize) {
/*вычисляем минимальное значение, между длиной массива и текущим последним
* индексом создаваемого сегмента*/
int min = Math.min(files.length, i + partitionSize);
/* Проверяем, нужно ли включать остаток в последний сегмент*/
boolean isLastChunk = false;
if((i + partitionSize) >= bound){
isLastChunk = true;
}
int endIndexRange;
/*определяем последний индекс файла в текущем создаваемом сегменте*/
if (includeRest && isLastChunk) {
endIndexRange = files.length; /*если в сегментах четное число файлов*/
} else {
endIndexRange = min;
}
File[] filesResult = Arrays.copyOfRange(files, i, endIndexRange);
resultArr.add(filesResult);
}
return resultArr;
}