Как «застегнуть» или «повернуть» переменное количество списков?

Если у меня есть список, содержащий произвольное количество списков, например:

var myList = new List<List>() { new List() { "a", "b", "c", "d" }, new List() { "1", "2", "3", "4" }, new List() { "w", "x", "y", "z" }, // ...etc... }; 

… есть ли какой-либо способ «застегнуть» или «повернуть» списки в нечто подобное?

 { { "a", "1", "w", ... }, { "b", "2", "x", ... }, { "c", "3", "y", ... }, { "d", "4", "z", ... } } 

Очевидным решением было бы сделать что-то вроде этого:

 public static IEnumerable<IEnumerable> Rotate(this IEnumerable<IEnumerable> list) { for (int i = 0; i  x.Count()); i++) { yield return list.Select(x => x.ElementAt(i)); } } // snip var newList = myList.Rotate(); 

… но мне было интересно, есть ли более чистый способ сделать это, используя linq или иначе?

Вы можете свернуть собственный экземпляр ZipMany, который вручную выполняет итерацию каждого из перечислений. Вероятно, это будет лучше для больших последовательностей, чем те, которые используют GroupBy после проецирования каждой последовательности:

 public static IEnumerable ZipMany( IEnumerable> source, Func, TResult> selector) { // ToList is necessary to avoid deferred execution var enumerators = source.Select(seq => seq.GetEnumerator()).ToList(); try { while (true) { foreach (var e in enumerators) { bool b = e.MoveNext(); if (!b) yield break; } // Again, ToList (or ToArray) is necessary to avoid deferred execution yield return selector(enumerators.Select(e => e.Current).ToList()); } } finally { foreach (var e in enumerators) e.Dispose(); } } 

Вы можете сделать это, используя расширение Select , используя Func :

 var rotatedList = myList.Select(inner => inner.Select((s, i) => new {s, i})) .SelectMany(a => a) .GroupBy(a => ai, a => as) .Select(a => a.ToList()).ToList(); 

Это даст вам другой List> .

Сломать

 .Select(inner => inner.Select((s, i) => new {s, i})) 

Для каждого внутреннего списка мы проецируем содержимое списка на новый анонимный объект с двумя свойствами: s , строковое значение и i индекс этого значения в исходном списке.

 .SelectMany(a => a) 

Мы сглаживаем результат до одного списка

 .GroupBy(a => ai, a => as) 

Мы группируем по свойству i нашего анонимного объекта (напомним, что это индекс) и выбираем свойство s как наши значения (только строка).

 .Select(a => a.ToList()).ToList(); 

Для каждой группы мы перечислили перечислимый список и другой список для всех групп.

Как насчет использования SelectMany и GroupBy с некоторыми индексами?

 // 1. Project inner lists to a single list (SelectMany) // 2. Use "GroupBy" to aggregate the item's based on order in the lists // 3. Strip away any ordering key in the final answer var query = myList.SelectMany( xl => xl.Select((vv,ii) => new { Idx = ii, Value = vv })) .GroupBy(xx => xx.Idx) .OrderBy(gg => gg.Key) .Select(gg => gg.Select(xx => xx.Value)); 

От LinqPad:

мы группируем элементы

Вот неэффективный вариант, основанный на трансформации матрицы:

 public static class Ext { public static IEnumerable> Rotate( this IEnumerable> src) { var matrix = src.Select(subset => subset.ToArray()).ToArray(); var height = matrix.Length; var width = matrix.Max(arr => arr.Length); T[][] transpose = Enumerable .Range(0, width) .Select(_ => new T[height]).ToArray(); for(int i=0; i 

Взгляните на проект linqlib на codeplex , он имеет функцию поворота, которая делает именно то, что вам нужно.

Вы можете конденсироваться for циклов, используя Range :

 var result = Enumerable.Range(0, myList.Min(l => l.Count)) .Select(i => myList.Select(l => l[i]).ToList()).ToList(); 
 (from count in Range(myList[0].Count) select new List( from count2 in Range(myList.Count) select myList[count2][count]) ).ToList(); 

Это некрасиво, но я думаю, что это сработает.

  • Поиск дубликатов в O (n) времени и O (1) пространстве
  • алгоритм проверки соединения четырех полей
  • Как сравнивается алгоритм Дейкстры и A-Star?
  • Сокращения параллельно в логарифмическом времени
  • Самый элегантный способ генерации простых чисел
  • Найдите, находится ли точка внутри выпуклой оболочки для набора точек без вычисления самого корпуса
  • Преобразование равномерного распределения в нормальное распределение
  • Самый быстрый алгоритм проверки прочности
  • Обнаружение столкновений огромного количества кругов
  • Как эффективно объединить два BST?
  • Вычисление положения точек в круге
  • Interesting Posts

    Если async-wait не создает никаких дополнительных streamов, то как это реагирует на приложения?

    Добавить водосточный желоб (привязка) к существующему файлу PDF

    Как убить процесс, который в настоящее время использует порт на localhost в Windows?

    Запуск Windows с USB-диска

    Преобразование магнитного поля X, Y, Z значений из устройства в глобальную систему отсчета

    Как я могу восстановить разбитый жесткий диск?

    Объявления переменных после операторов if

    Разрешить Java использовать ненадежный сертификат для соединения SSL / HTTPS

    Каковы возможные причины, по которым DNS-сервер моей компании иногда не может решить имя хоста некоторых из моих виртуальных машин?

    RDP wake-on-lan в локальной сети

    Клавиатура не отображается при нажатии текстового поля в UIWebView

    Есть ли лимит процессора для Mac OS X?

    Spring MVC – AngularJS – Загрузка файлов – org.apache.commons.fileupload.FileUploadException

    Ненужные обновления Office предлагаются?

    Как найти идентификатор процесса (pid) процесса, запущенного в java?

    Давайте будем гением компьютера.