Распределить объекты равномерно по группам

Есть лист с участниками - допустим 41 объект

Их нужно равномерно распределить в группы до 8 участников

Итоговое количество групп узнаётся через 41 / 8 + 1

Теперь нужно распределить участников между этими группами, что бы получилось следующее:

1 группа - 7 участников
2 группа - 7 участников
3 группа - 7 участников
4 группа - 7 участников
5 группа - 7 участников
6 группа - 6 участников

Однако, вариант с "по очереди добавлять одного участника в группу пока участники не закончатся" - не подходит, поскольку нужно участников добавлять пачками, т.е., в данном случае, первые 7 участников в группу 1, потом следующие 7 участников в группу 2

Можно, конечно, сначала считать в отдельном листе кол-во участников, которое должно быть в группах, и после, используя этот лист, делить участников на пачки для групп. Но можно ли придумать более элегантный алгоритм?


Ответы (2 шт):

Автор решения: MBo

Чтобы получить количество групп с бОльшим населением:

N = 41
Size = 8
NGroups = (N + Size - 1) / Size
NLargeGroups = N - N / NGroups * NGroups

Полный пример на Python

→ Ссылка
Автор решения: VladD

Вот в принципе то же вычисление, что и в ответе @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

→ Ссылка