Распределить объекты равномерно по группам
Есть лист с участниками - допустим 41 объект
Их нужно равномерно распределить в группы до 8 участников
Итоговое количество групп узнаётся через 41 / 8 + 1
Теперь нужно распределить участников между этими группами, что бы получилось следующее:
1 группа - 7 участников
2 группа - 7 участников
3 группа - 7 участников
4 группа - 7 участников
5 группа - 7 участников
6 группа - 6 участников
Однако, вариант с "по очереди добавлять одного участника в группу пока участники не закончатся" - не подходит, поскольку нужно участников добавлять пачками, т.е., в данном случае, первые 7 участников в группу 1, потом следующие 7 участников в группу 2
Можно, конечно, сначала считать в отдельном листе кол-во участников, которое должно быть в группах, и после, используя этот лист, делить участников на пачки для групп. Но можно ли придумать более элегантный алгоритм?
Ответы (2 шт):
Чтобы получить количество групп с бОльшим населением:
N = 41
Size = 8
NGroups = (N + Size - 1) / Size
NLargeGroups = N - N / NGroups * NGroups
Вот в принципе то же вычисление, что и в ответе @MBo, на C#, плюс я разбил элементы на группы.
var totalNumberOfItems = 41;
var maxGroupSize = 8;
var items = Enumerable.Range(1, totalNumberOfItems).Select(n => $"Item #{n}").ToList();
// сколько всего групп
var nGroups = (int)Math.Ceiling((double)totalNumberOfItems / maxGroupSize);
// какое максимальное количество участников в группе
var fullGroupSize = (int)Math.Ceiling((double)totalNumberOfItems / nGroups);
// сколько не хватает, чтобы все группы были полными
var deficit = nGroups * fullGroupSize - totalNumberOfItems;
// -> столько групп будут неполными
var nFullGroups = nGroups - deficit;
var fullGroupsTotal = nFullGroups * fullGroupSize;
// подсчитаем номер группы по индексу
int GroupIndex(int itemIndex) =>
itemIndex < fullGroupsTotal ? // попадает в полную группу?
itemIndex / fullGroupSize : // считаем по fullGroupSize в группе
(itemIndex - fullGroupsTotal) / (fullGroupSize - 1) + nFullGroups;
// иначе считаем по fullGroupSize - 1
var groups =
items.Select((item, idx) => (item, groupNo: GroupIndex(idx)))
.GroupBy(pair => pair.groupNo, pair => pair.item)
.OrderBy(g => g.Key)
.Select(g => g.ToList());
foreach (var group in groups)
Console.WriteLine($"[ {string.Join(", ", group)} ] ({group.Count} items)");
Проверка: https://dotnetfiddle.net/QAUhW6