在C#中联合多个列表

时间:2011-08-04 21:13:18

标签: c# linq list extension-methods

我正在为以下情况寻找一个优雅的解决方案:

我有一个包含像

这样的列的类
class MyClass{ 
...
 public List<SomeOtherClass> SomeOtherClassList {get; set;}
...
}

第三个名为Model的班级拥有一个List<Myclass>,这是我从外部进行的操作。

现在我想扩展Model类,该方法返回所有MyClass实例上所有唯一的SomeOtherClass实例。

我知道有Union()方法和foreach循环我可以轻松解决这个问题,我实际上已经做到了。但是,由于我是所有C#3 +功能的新手,我很好奇如何在有或没有Linq的情况下更优雅地实现这一目标。

我找到了一种方法,对我来说似乎相当笨拙,但它有效:

        List<SomeOtherClass> ret = new List<SomeOtherClass>();
        MyClassList.Select(b => b.SomeOtherClasses).ToList().ForEach(l => ret = ret.Union(l).ToList()); 
        return ret;

注意:b.SomeotherClasses属性返回List<SomeOtherClasses>

这段代码远非完美,而且有些问题来自于我必须弄清楚什么是使用C#3的好风格以及什么不是。所以,我提出了一个关于该片段的小清单,我很乐意得到一些评论。除此之外,我很高兴听到一些评论如何进一步改进此代码。

  • 临时列表ret可能是C#2中的一种方法的一部分,但是我应该能够使用方法链来重新签名此列表是否正确?或者我错过了这一点?
  • 是否真的需要使用中间ToList()方法?我想要的只是对选择中的每个成员进行进一步的操作。
  • 那些ToList()操作的成本是多少?他们风格好吗?必要?

感谢。

2 个答案:

答案 0 :(得分:26)

您正在寻找SelectMany() + Distinct()

List<SomeOtherClass> ret =  MyClassList.SelectMany( x => x.SomeOtherClasses)
                                       .Distinct()
                                       .ToList();

SelectMany()会将“列表列表”压缩到一个列表中,然后您可以选择此枚举中的不同条目,而不是使用各个子列表之间的联合。

一般情况下,你会希望避免使用Linq的副作用,你的原始方法有点滥用我的修改ret,这不是查询的一部分。

ToList()是必需的,因为每个标准查询运算符都返回一个新的枚举,并且不会修改现有的枚举,因此您必须将最终的枚举结果转换回列表。 ToList()的成本是枚举的完整迭代,在大多数情况下,这可以忽略不计。当然,如果您的班级可以使用IEnumerable<SomeOtherClass>,则您根本不必转换为列表。

答案 1 :(得分:0)

你应该看看SelectMany。这样的事情应该产生你的“平面”列表:

MyClassList.SelectMany(b => b.SomeOtherClasses)

它将返回IEnumerable<SomeOtherClass>,您可以进一步过滤/处理。