我正在为以下情况寻找一个优雅的解决方案:
我有一个包含像
这样的列的类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()
方法?我想要的只是对选择中的每个成员进行进一步的操作。感谢。
答案 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>
,您可以进一步过滤/处理。