C# 合并多个列表
假设我有一个列表列表,C# 合并多个列表,c#,.net,linq,list,C#,.net,Linq,List,假设我有一个列表列表,list,其中所有列表都包含0个或多个项目,很可能,但不一定都是相同的数字。我想要一份包含所有项目的清单。。。但我希望顺序如下:首先是所有列表中的第一项,以便它们出现在“超级列表”中 前 (注意这不是字母顺序,蓝莓在狒狒之前) 当然,只要列表不是空的,我可以使用计数器循环“superlist”,将项目逐个添加到resultslist: int i = 0; bool done = false; while (!done) { bool found = false;
list
,其中所有列表都包含0个或多个项目,很可能,但不一定都是相同的数字。我想要一份包含所有项目的清单。。。但我希望顺序如下:首先是所有列表中的第一项,以便它们出现在“超级列表”中
前
(注意这不是字母顺序,蓝莓在狒狒之前)
当然,只要列表不是空的,我可以使用计数器循环“superlist”,将项目逐个添加到resultslist:
int i = 0;
bool done = false;
while (!done)
{
bool found = false;
foreach (list l in superlist)
{
if (l.Count() > i)
{
found = true;
result.Add(l[i]);
}
}
i++;
if (!found)
done = true;
}
但使用一些优化的LINQ函数来实现这一点会更好。我一直在调查,但没能让他们工作
那么:是否有一个漂亮的LINQ函数,或者多个函数的组合,可以将其转化为漂亮的代码,或者我应该坚持(或者优化)我当前的函数
编辑:一个简单的SelectMany(x=>x)也不起作用,因为它保留了列表的顺序,而不是像我的算法那样折叠列表。有关更多详细信息,请参阅我的初始问题。您需要
选择多个
var result = lists.SelectMany(x => x.Select((s, inx) => new { s, inx }))
.GroupBy(x => x.inx)
.SelectMany(x => x.Select(y => y.s))
.ToList();
编辑
对于那些想要尝试的人,初始化代码
List<List<string>> lists = new List<List<string>>()
{
new List<string>(){ "Apple", "Blueberry", "Cranberry" },
new List<string>(){ "Anteater", "Baboon", "Camel", "Dodo"},
new List<string>(){ "Albatross", "Blackbird", "Chicken"},
};
列表列表=新列表()
{
新列表(){“苹果”、“蓝莓”、“蔓越莓”},
新列表(){“食蚁兽”、“狒狒”、“骆驼”、“渡渡鸟”},
新列表(){“信天翁”、“黑鸟”、“鸡”},
};
编辑2
输出:苹果、食蚁兽、信天翁、蓝莓、狒狒、黑鸟、蔓越莓、骆驼、鸡、渡渡鸟
只需使用MyListOfLists。选择多个(x=>x)。按降序排列(x=>x)。ToList()
SelectMany会将您的列表展平为一个列表。OrderByDescending对该结果进行操作,并将结果按字母顺序排列(我想这是您想要的)。然后调用ToList
强制执行并获取一个List
而不是IEnumerable
用于展平列表中的项目并从中创建一个新列表
var result = superlist.SelectMany(r=> r).ToList();
如果列表包含不同的项,并且列表中没有重复的项,则此操作有效
var result = list.SelectMany(x=>x)
.OrderBy(x=>list.First(a=>a.Contains(x))
.IndexOf(x));
如何使用内置linq扩展从所有列表中选择第一个元素,然后选择第二个元素,等等,没有简单或最佳的方法(通过性能和代码可读性)。但是,您可以从代码中构建自己的扩展,或者如果您不喜欢while
循环,如下所示:
public static class MyLinqExtensions
{
public static void MySelect<T>(this IEnumerable<IEnumerable<T>> superlist)
{
int index = 0;
foreach (IEnumerable<T> list in superlist)
{
if (index < list.Count())
{
yield return list.ElementAt(index);
}
index++;
}
}
}
公共静态类MyLinqExtensions
{
公共静态void MySelect(此IEnumerable超级列表)
{
int指数=0;
foreach(超级列表中的IEnumerable列表)
{
if(索引
最后,您可以在结果上调用Enumerable.Distinct()
,以获得唯一值。我知道您要做什么:
var result = input.SelectMany(l => l.Select((o, i) => new { o, i })).GroupBy(o => o.i).OrderBy(g => g.Key).SelectMany(g => g.Select(o => o.o);
我知道我参加聚会迟到了,但由于这篇文章是从我正在做的另一篇文章中引用的,作为解决问题的基础,我觉得有必要在这个主题上添加一些东西
在这个问题上有两种相互矛盾的说法:
但使用一些优化的LINQ函数来实现这一点会更好
然后
那么:是否有一个漂亮的LINQ函数,或者多个函数的组合,可以将其转化为漂亮的代码,或者我应该坚持(或者优化)我当前的函数
优化的和漂亮的之间有很大的区别。当然,这取决于“优化”的含义。漂亮、可读、较短的代码可能被认为是针对维护而优化的,但大多数情况下不是针对性能。因此,让我们谈谈性能。被接受的答案可能看起来很酷,但在时间和空间上都是低效的(由于group by),甚至没有提供类似“标准LINQ”Concat
函数的延迟执行行为
在这方面,OP提供的原始功能要好得多。但我们可以更进一步,创建一个更通用的函数(不需要列表),它可以有效地完成所有这些,同时遵循LINQ实现的精神:
static class Extensions
{
public static IEnumerable<T> Merge<T>(this IEnumerable<IEnumerable<T>> source)
{
var queue = new Queue<IEnumerator<T>>();
IEnumerator<T> itemEnumerator = null;
try
{
// First pass: yield the first element (if any) and schedule the next (if any)
foreach (var list in source)
{
itemEnumerator = list.GetEnumerator();
if (!itemEnumerator.MoveNext())
itemEnumerator.Dispose();
else
{
yield return itemEnumerator.Current;
if (itemEnumerator.MoveNext())
queue.Enqueue(itemEnumerator);
else
itemEnumerator.Dispose();
}
}
// Second pass: yield the current element and schedule the next (if any)
while (queue.Count > 0)
{
itemEnumerator = queue.Dequeue();
yield return itemEnumerator.Current;
if (itemEnumerator.MoveNext())
queue.Enqueue(itemEnumerator);
else
itemEnumerator.Dispose();
}
}
finally
{
if (itemEnumerator != null) itemEnumerator.Dispose();
while (queue.Count > 0) queue.Dequeue().Dispose();
}
}
}
静态类扩展
{
公共静态IEnumerable合并(此IEnumerable源)
{
var queue=新队列();
IEnumerator itemEnumerator=null;
尝试
{
//第一次通过:产生第一个元素(如有)并安排下一个元素(如有)
foreach(源中的变量列表)
{
itemEnumerator=list.GetEnumerator();
如果(!itemEnumerator.MoveNext())
itemEnumerator.Dispose();
其他的
{
产生返回itemEnumerator.Current;
if(itemEnumerator.MoveNext())
排队(itemEnumerator);
其他的
itemEnumerator.Dispose();
}
}
//第二步:生成当前元素并计划下一步(如果有)
而(queue.Count>0)
{
itemEnumerator=queue.Dequeue();
产生返回itemEnumerator.Current;
if(itemEnumerator.MoveNext())
排队(itemEnumerator);
其他的
itemEnumerator.Dispose();
}
}
最后
{
如果(itemEnumerator!=null)itemEnumerator.Dispose();
而(queue.Count>0)queue.Dequeue().Dispose();
}
}
}
请注意,我可以通过消除重复部分并合并两个过程轻松地缩短它,但这会降低可读性,而不会加快速度(事实上是这样的)
static class Extensions
{
public static IEnumerable<T> Merge<T>(this IEnumerable<IEnumerable<T>> source)
{
var queue = new Queue<IEnumerator<T>>();
IEnumerator<T> itemEnumerator = null;
try
{
// First pass: yield the first element (if any) and schedule the next (if any)
foreach (var list in source)
{
itemEnumerator = list.GetEnumerator();
if (!itemEnumerator.MoveNext())
itemEnumerator.Dispose();
else
{
yield return itemEnumerator.Current;
if (itemEnumerator.MoveNext())
queue.Enqueue(itemEnumerator);
else
itemEnumerator.Dispose();
}
}
// Second pass: yield the current element and schedule the next (if any)
while (queue.Count > 0)
{
itemEnumerator = queue.Dequeue();
yield return itemEnumerator.Current;
if (itemEnumerator.MoveNext())
queue.Enqueue(itemEnumerator);
else
itemEnumerator.Dispose();
}
}
finally
{
if (itemEnumerator != null) itemEnumerator.Dispose();
while (queue.Count > 0) queue.Dequeue().Dispose();
}
}
}