Это то же самое, что и принятый ответ, но в гораздо более простом представлении:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> items,
int numOfParts)
{
int i = 0;
return items.GroupBy(x => i++ % numOfParts);
}
Вышеупомянутый метод разбивает IEnumerable<T>
на N частей равного или почти равного размера.
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items,
int partitionSize)
{
int i = 0;
return items.GroupBy(x => i++ / partitionSize).ToArray();
}
Вышеупомянутый метод разбивает IEnumerable<T>
на куски желаемого фиксированного размера, при этом общее количество кусков не имеет значения - вопрос не в этом.
Проблема с Split
методом, помимо того, что он медленнее, заключается в том, что он скремблирует вывод в том смысле, что группировка будет выполняться на основе i-го числа, кратного N для каждой позиции, или, другими словами, вы не получаете куски в исходном порядке.
Почти каждый ответ здесь либо не сохраняет порядок, либо касается разделения, а не разделения, либо явно неверен. Попробуйте это быстрее, с сохранением порядка, но немного более подробным:
public static IEnumerable<IEnumerable<T>> Split<T>(this ICollection<T> items,
int numberOfChunks)
{
if (numberOfChunks <= 0 || numberOfChunks > items.Count)
throw new ArgumentOutOfRangeException("numberOfChunks");
int sizePerPacket = items.Count / numberOfChunks;
int extra = items.Count % numberOfChunks;
for (int i = 0; i < numberOfChunks - extra; i++)
yield return items.Skip(i * sizePerPacket).Take(sizePerPacket);
int alreadyReturnedCount = (numberOfChunks - extra) * sizePerPacket;
int toReturnCount = extra == 0 ? 0 : (items.Count - numberOfChunks) / extra + 1;
for (int i = 0; i < extra; i++)
yield return items.Skip(alreadyReturnedCount + i * toReturnCount).Take(toReturnCount);
}
Эквивалентный метод Partition
операции здесь