LINQ для строк

Недавно проводил на работе мини-олимпиаду по программированию. Включил одну задачу на LINQ, так как эта технология уже в каждом проекте так и лезет.

Задача звучит так:

Имеется длинная строка символов. Необходимо одним выражением LINQ получить набор строк, представляющих собой разбиение исходной строки на подстроки с одинаковым числом символов (тип результата IEnumerable<string>).

Исходная строкаРезультат
Разбить на строки ABCDEFGHIJKLMNOPQRSTUVWXYZZZZZZZZ.
Разбить на с
троки ABCDEF
GHIJKLMNOPQR
STUVWXYZZZZZ
ZZZ.
Допустимо использовать любые стандартные фукнции, дополнительные переменные, анонимные типы и лямбда-выражения, синтаксис запросов LINQ либо методов расширений. Недопустимо использовать в запросе операторы цикла.

Один из наиболее “навороченных” вариантов решения:

var res =
    str.Select((c, i) =>
       					// Разбиваем строку на символы с номерами
        new
        {
            Value = c,              // Символ
            Index = i,              // Позиция символа в изначальной строке
            LineNumber = i / width  // Номер строки
        }
    )
.GroupBy(g => g.LineNumber, e => e) // Объединяем символы одной строки
.Select(ar => ar.Select(ars => ars.Value))
.Select(outs => new string(outs.ToArray())); // Склеиваем символы обратно в строки

Это наиболее “чистый” LINQ-запрос, не использующий никаких дополнительных средств, кроме создания строк из массива символов. Используется вариант метода Select(), позволяющий работать с индексом элемента во входной последовательности.

Другой вариант жюри предполагал использование метода Enumerable.Range() как замену цикла. Здесь основная идея в том, что мы можем заранее определить, сколько строк получится в результате, а по номеру символа в строке узнать, к какой строке он относится:

var res = Enumerable
.Range(0, str.Length / width + 1) // Массив номеров будущих строк
.Join(
    str.ToCharArray().Select((c, i) =>
    {  // Разбиваем строку на символы с номерами
        return new { Value = c, Index = i };
    }),
    s => s,
    d => d.Index / width, // По номеру символа определяем, к какой строке он будет относится
    (s, d) => new { s, d })
.GroupBy(g => g.s, e => e) // Объединяем символы одной строки
.Select(ar => ar.Select(ars => ars.d.Value))
.Select(outs => new string(outs.ToArray())); // Склеиваем символы обратно в строки

Это решение можно упростить до примитивного (но тем не менее корректного):

var res = Enumerable
.Range(0, str.Length / width + 1) // Массив номеров будущих строк
.Select(s => str.Substring(s * width, Math.Min(width, str.Length - s * width))); // Выберем подстроки