旋转 – 使用LINQ C#转置列表<List >

我有一个List<List> ,它是从远程数据源(即WCF)返回的。 因此,我需要使用LINQ将以下数据修改为用户友好的列表

C#代码是

 List<List> PersonInfo = new List<List>() { new List() {"John", "Peter", "Watson"}, new List() {"1000", "1001", "1002"} } 

适当的屏幕截图: 现有的

在此处输入图像描述

我需要旋转数据,如下面的屏幕截图: 建议

在此处输入图像描述

请帮助我如何使用LINQ C#旋转数据

这是一个简单而灵活的解决方案,它将处理具有任意数量维度的多个内部列表。

 List> PersonInfo = new List>() { new List() {"John", "Peter", "Watson"}, new List() {"1000", "1001", "1002"} }; var result = PersonInfo .SelectMany(inner => inner.Select((item, index) => new { item, index })) .GroupBy(i => i.index, i => i.item) .Select(g => g.ToList()) .ToList(); 

这是一种扩展方法

 public static IEnumerable> Pivot(this IEnumerable> source) { var enumerators = source.Select(e => e.GetEnumerator()).ToArray(); try { while (enumerators.All(e => e.MoveNext())) { yield return enumerators.Select(e => e.Current).ToArray(); } } finally { Array.ForEach(enumerators, e => e.Dispose()); } } 

所以你可以

 var result = PersonInfo.Pivot(); 

假设PersonInfo中只有2个列表:

 var rotated = PersonInfo[0] .Zip(PersonInfo[1], (a, b) => new List { a, b }).ToList(); 

如果PersonInfo中可以有任意数量的列表:

 Enumerable.Range(0, PersonInfo[0].Count) .Select(i => PersonInfo.Select(lst => lst[i]).ToList()).ToList(); 

您可以使用Enumerable.RangeEnumerable.ElementAtOrDefault

 List> rotated = Enumerable.Range(0, PersonInfo.Max(list => list.Count)) .Select(i => PersonInfo.Select(list => list.ElementAtOrDefault(i)).ToList()) .ToList(); 

PersonInfo.Max(list => list.Count)返回PersonInfo.Max(list => list.Count)的最大大小。 这将是主列表的新大小,在本例中为3. Enumerable.Range就像一个for循环。 对于每个列表,它现在将选择这些索引处的所有字符串。 如果大小不同,您将获得null (因为ElementAtOrDefault )。

如果列表具有相同的大小,您可以应用相同的查询来获取原始列表:

 PersonInfo = Enumerable.Range(0, rotated.Max(list => list.Count)) .Select(i => rotated.Select(list => list.ElementAtOrDefault(i)).ToList()) .ToList(); 

作为扩展:

 public static IEnumerable> Rotate(this IEnumerable> sequences) { var list = sequences as IList> ?? sequences.ToList(); int maxCount = list.Max(l => l.Count); return Enumerable.Range(0, maxCount) .Select(i => list.Select(l => l.ElementAtOrDefault(i)).ToList()); } 

用法:

 IEnumerable> rotated = PersonInfo.Rotate(); IEnumerable> rotatedPersonInfo = rotated.Rotate(); // append ToList to get the original list 

这将上面的Zip概念扩展到任意数量的列表。 Zip会将行列表截断为最小的排名。

 List> PersonInfo = new List>() { new List() {"John", "Peter", "Watson"}, new List() {"1000", "1001", "1002"}, new List() {"2000", "2001", "2002"}, new List() {"3000", "3001", "3002"} }; var seed = Enumerable.Empty>(); var transformed = PersonInfo.Aggregate(seed, (acc, r) => acc.Any() ? acc.Zip(r, (row, nextElement) => { row.Add(nextElement); return row; }) : r.Select(e => new List { e }) //initialize target list using first row ); 

试试这个:

 List> PersonInfo = new List>(){ new List() {"John", "Peter", "Watson"}, new List() {"1000", "1001", "1002"}}; List> PivitedPersonInfo = new List>(); for (int i = 0; i < PersonInfo.First().Count; i++) { PivitedPersonInfo.Add(PersonInfo.Select(x => x.ElementAt(i)).ToList()); }