旋转 - 使用 LINQ C# 转置列表<List<string>>
Rotate - Transposing a List<List<string>> using LINQ C#
我有一个 List<List<string>>
,它是来自远程数据源(即 WCF)的 return。因此,我需要使用 LINQ
将以下数据修改为用户友好的列表
C#代码是
List<List<string>> PersonInfo = new List<List<string>>()
{
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"1000", "1001", "1002"}
}
适当的屏幕截图:现有
我需要像下面的截图一样旋转数据:建议
请帮助我如何使用 LINQ C#
旋转数据
试试这个:
List<List<string>> PersonInfo = new List<List<string>>(){
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"1000", "1001", "1002"}};
List<List<string>> PivitedPersonInfo = new List<List<string>>();
for (int i = 0; i < PersonInfo.First().Count; i++)
{
PivitedPersonInfo.Add(PersonInfo.Select(x => x.ElementAt(i)).ToList());
}
假设 PersonInfo
中只有 2 个列表:
var rotated = PersonInfo[0]
.Zip(PersonInfo[1], (a, b) => new List<string> { a, b }).ToList();
如果 PersonInfo 中可以有任意数量的列表:
Enumerable.Range(0, PersonInfo[0].Count)
.Select(i => PersonInfo.Select(lst => lst[i]).ToList()).ToList();
这是一个通用的扩展方法
public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> 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();
这是一个简单而灵活的解决方案,它将处理具有任意维数的多个内部列表。
List<List<string>> PersonInfo = new List<List<string>>()
{
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"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();
您可以使用 Enumerable.Range
和 Enumerable.ElementAtOrDefault
:
List<List<string>> rotated = Enumerable.Range(0, PersonInfo.Max(list => list.Count))
.Select(i => PersonInfo.Select(list => list.ElementAtOrDefault(i)).ToList())
.ToList();
PersonInfo.Max(list => list.Count)
returns 列表的最大大小。这将是主列表的新大小,在本例中为 3。 Enumerable.Range
就像一个 for 循环。对于每个列表,它现在将 select 这些索引处的所有字符串。如果尺寸不同,您将得到 null
(因为 ElementAtOrDefault
)。
如果列表的大小相同,您可以应用相同的查询来取回原始列表:
PersonInfo = Enumerable.Range(0, rotated.Max(list => list.Count))
.Select(i => rotated.Select(list => list.ElementAtOrDefault(i)).ToList())
.ToList();
作为扩展名:
public static IEnumerable<IList<T>> Rotate<T>(this IEnumerable<IList<T>> sequences)
{
var list = sequences as IList<IList<T>> ?? sequences.ToList();
int maxCount = list.Max(l => l.Count);
return Enumerable.Range(0, maxCount)
.Select(i => list.Select(l => l.ElementAtOrDefault(i)).ToList());
}
用法:
IEnumerable<IList<string>> rotated = PersonInfo.Rotate();
IEnumerable<IList<string>> rotatedPersonInfo = rotated.Rotate(); // append ToList to get the original list
这将上面的 Zip 想法扩展到任意数量的列表。 Zip 会将行列表截断到最小级别。
List<List<string>> PersonInfo = new List<List<string>>()
{
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"1000", "1001", "1002"},
new List<string>() {"2000", "2001", "2002"},
new List<string>() {"3000", "3001", "3002"}
};
var seed = Enumerable.Empty<List<string>>();
var transformed = PersonInfo.Aggregate(seed, (acc, r) =>
acc.Any()
? acc.Zip(r, (row, nextElement) => { row.Add(nextElement); return row; })
: r.Select(e => new List<string> { e }) //initialize target list using first row
);
只需执行以下操作:
var persons = Enumerable.Range(0, PersonInfo.First().Count()).Select(i => PersonInfo.Select(e => e[i]).ToList()).ToList();
或
var persons = Enumerable.Range(0, PersonInfo[0].Count()).Select(i => {
return PersonInfo.Select(e => {
return e[i];
}).ToList();
}).ToList();
并检查如下结果:
persons.ForEach(p => Console.WriteLine("{0} {1}", p[0], p[1]));
我有一个 List<List<string>>
,它是来自远程数据源(即 WCF)的 return。因此,我需要使用 LINQ
C#代码是
List<List<string>> PersonInfo = new List<List<string>>()
{
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"1000", "1001", "1002"}
}
适当的屏幕截图:现有
我需要像下面的截图一样旋转数据:建议
请帮助我如何使用 LINQ C#
旋转数据试试这个:
List<List<string>> PersonInfo = new List<List<string>>(){
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"1000", "1001", "1002"}};
List<List<string>> PivitedPersonInfo = new List<List<string>>();
for (int i = 0; i < PersonInfo.First().Count; i++)
{
PivitedPersonInfo.Add(PersonInfo.Select(x => x.ElementAt(i)).ToList());
}
假设 PersonInfo
中只有 2 个列表:
var rotated = PersonInfo[0]
.Zip(PersonInfo[1], (a, b) => new List<string> { a, b }).ToList();
如果 PersonInfo 中可以有任意数量的列表:
Enumerable.Range(0, PersonInfo[0].Count)
.Select(i => PersonInfo.Select(lst => lst[i]).ToList()).ToList();
这是一个通用的扩展方法
public static IEnumerable<IEnumerable<T>> Pivot<T>(this IEnumerable<IEnumerable<T>> 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();
这是一个简单而灵活的解决方案,它将处理具有任意维数的多个内部列表。
List<List<string>> PersonInfo = new List<List<string>>()
{
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"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();
您可以使用 Enumerable.Range
和 Enumerable.ElementAtOrDefault
:
List<List<string>> rotated = Enumerable.Range(0, PersonInfo.Max(list => list.Count))
.Select(i => PersonInfo.Select(list => list.ElementAtOrDefault(i)).ToList())
.ToList();
PersonInfo.Max(list => list.Count)
returns 列表的最大大小。这将是主列表的新大小,在本例中为 3。 Enumerable.Range
就像一个 for 循环。对于每个列表,它现在将 select 这些索引处的所有字符串。如果尺寸不同,您将得到 null
(因为 ElementAtOrDefault
)。
如果列表的大小相同,您可以应用相同的查询来取回原始列表:
PersonInfo = Enumerable.Range(0, rotated.Max(list => list.Count))
.Select(i => rotated.Select(list => list.ElementAtOrDefault(i)).ToList())
.ToList();
作为扩展名:
public static IEnumerable<IList<T>> Rotate<T>(this IEnumerable<IList<T>> sequences)
{
var list = sequences as IList<IList<T>> ?? sequences.ToList();
int maxCount = list.Max(l => l.Count);
return Enumerable.Range(0, maxCount)
.Select(i => list.Select(l => l.ElementAtOrDefault(i)).ToList());
}
用法:
IEnumerable<IList<string>> rotated = PersonInfo.Rotate();
IEnumerable<IList<string>> rotatedPersonInfo = rotated.Rotate(); // append ToList to get the original list
这将上面的 Zip 想法扩展到任意数量的列表。 Zip 会将行列表截断到最小级别。
List<List<string>> PersonInfo = new List<List<string>>()
{
new List<string>() {"John", "Peter", "Watson"},
new List<string>() {"1000", "1001", "1002"},
new List<string>() {"2000", "2001", "2002"},
new List<string>() {"3000", "3001", "3002"}
};
var seed = Enumerable.Empty<List<string>>();
var transformed = PersonInfo.Aggregate(seed, (acc, r) =>
acc.Any()
? acc.Zip(r, (row, nextElement) => { row.Add(nextElement); return row; })
: r.Select(e => new List<string> { e }) //initialize target list using first row
);
只需执行以下操作:
var persons = Enumerable.Range(0, PersonInfo.First().Count()).Select(i => PersonInfo.Select(e => e[i]).ToList()).ToList();
或
var persons = Enumerable.Range(0, PersonInfo[0].Count()).Select(i => {
return PersonInfo.Select(e => {
return e[i];
}).ToList();
}).ToList();
并检查如下结果:
persons.ForEach(p => Console.WriteLine("{0} {1}", p[0], p[1]));