C# 组合多个元素集合的优雅方式?
假设我有任意数量的集合,每个集合包含相同类型的对象(例如,C# 组合多个元素集合的优雅方式?,c#,linq,generics,collections,C#,Linq,Generics,Collections,假设我有任意数量的集合,每个集合包含相同类型的对象(例如,listfoo和listbar)。如果这些集合本身在一个集合中(例如,类型为List),我可以使用SelectMany将它们组合成一个集合 但是,如果这些集合不在同一个集合中,我的印象是,我必须编写如下方法: public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine) { return toCombine.S
listfoo
和listbar
)。如果这些集合本身在一个集合中(例如,类型为List
),我可以使用SelectMany
将它们组合成一个集合
但是,如果这些集合不在同一个集合中,我的印象是,我必须编写如下方法:
public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
return toCombine.SelectMany(x => x);
}
var combined = Combine(foo, bar);
var list = list1.Concat(list2).Concat(list3);
有没有一种干净、优雅的方法可以组合(任意数量的)集合,而不必编写像上面的
combine
这样的实用方法?似乎很简单,在LINQ中应该有这样的方法,但可能没有。您可以按如下方式使用Union:
var combined=foo.Union(bar).Union(baz)...
但是,这将删除相同的元素,因此如果您有这些元素,您可能希望使用Concat
。使用:
我想你可能在找林克的
或者,
.Union()
将删除重复的元素。我看到的唯一方法是使用Concat()
或
有一点为什么Concat()
会是一个更好的选择是它对另一个开发人员来说更明显。更易读、更简单。像这样使用:
考虑到你从一堆独立的集合开始,我认为你的解决方案相当优雅。你必须做些事情把它们缝合在一起
从语法上来说,从Combine方法中生成一个扩展方法会更方便,这将使它可以在任何地方使用。对我来说
Concat
,因为当我有多个大序列要Concat时,扩展方法在我的代码中不是很优雅。这仅仅是一个代码缩进/格式化问题非常个人化
当然,它看起来像这样很好:
public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
return toCombine.SelectMany(x => x);
}
var combined = Combine(foo, bar);
var list = list1.Concat(list2).Concat(list3);
当它读起来像是:
var list = list1.Select(x = > x)
.Concat(list2.Where(x => true)
.Concat(list3.OrderBy(x => x));
或者当它看起来像:
return Normalize(list1, a, b)
.Concat(Normalize(list2, b, c))
.Concat(Normalize(list3, c, d));
或者不管你喜欢的格式是什么。更复杂的Concat会让事情变得更糟。我对上述风格的认知不一致的原因是第一个序列位于Concat
方法之外,而随后的序列位于内部。我更喜欢直接调用静态Concat
方法不是扩展样式:
var list = Enumerable.Concat(list1.Select(x => x),
list2.Where(x => true));
对于更多的连续序列,我采用与OP中相同的静态方法:
public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
return sequences.SelectMany(x => x);
}
看起来更好。考虑到我的序列在Concat
调用中看起来更干净,我必须编写的额外的、冗余的类名对我来说不是问题。在C#6中,这不是问题。您可以编写:
return Concat(list1.Select(x = > x),
list2.Where(x => true),
list3.OrderBy(x => x));
希望在C#中有列表串联运算符,类似于:
list1 @ list2 // F#
list1 ++ list2 // Scala
这样就更干净了。你可以用骨料和混凝土混合使用
var listOfLists = new List<List<int>>
{
new List<int> {1, 2, 3, 4},
new List<int> {5, 6, 7, 8},
new List<int> {9, 10}
};
IEnumerable<int> combined = new List<int>();
combined = listOfLists.Aggregate(combined, (current, list) => current.Concat(list)).ToList();
var listOfLists=新列表
{
新名单{1,2,3,4},
新名单{5,6,7,8},
新名单{9,10}
};
IEnumerable combined=新列表();
combined=listOfLists.Aggregate(combined,(current,list)=>current.Concat(list)).ToList();
对于确实有一组集合的情况,即列表
,可枚举。聚合
是将所有列表合并为一个列表的更优雅的方式:
var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });
对于任何
IEnumerable列表
,您只需要以下内容:
var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));
这将把
列表
中的所有项目合并为一个IEnumerable
(带有副本)。使用联合
而不是Concat
删除副本,如其他答案中所述。使用集合初始值设定项的两种技术--
假设这些列表:
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };
为Add定义一个列表扩展,该扩展允许在列表中IEnumerable
:
公共静态类集合扩展
{
公共静态无效添加(此ICollection集合,IEnumerable items)
{
foreach(项目中的var项目)集合。添加(项目);
}
}
然后,您可以创建一个新的列表,其中包含其他类似的元素(它还允许混合单个项目)
var combined=新列表{list1,list2,7,8};
否!可枚举。Union
是一个集合Union,它不会产生所需的结果(它只产生重复的一次).是的,我需要对象的特定实例,因为我需要对它们进行一些特殊处理。在我的示例中使用int
可能会让人有点不舒服;但是Union
在这种情况下对我不起作用。谢谢;我没有这样做的唯一原因是(对我而言)您需要处理的集合越多,它看起来就越难看。但是,这有使用现有LINQ函数的好处,未来的开发人员可能已经熟悉了这些函数。感谢.Union()
tip。请记住,如果需要的话,您需要在自定义类型上实现IComparer。我喜欢扩展方法的想法,如果LINQ已经有了一种方法可以做同样的事情,我只是不想重新发明轮子(并且很快就可以被其他开发人员理解)相关:注意Concat连接大量可枚举项,可能会炸毁堆栈:我感谢您对编码风格的关注。这更加优雅。也许您的答案的较小版本可以与顶部答案合并在一起。我也喜欢这种格式,尽管我更喜欢执行单独的列表操作(例如,Where
,OrderBy
)首先是为了清楚起见,特别是如果它们比这个例子更复杂的话。到目前为止,最好的解决方案是。@OlegSelectMany
更简单。你如何首先在这里获得列表呢?这是OP遇到的第一个问题。如果他有一个集合
,那么SelectMany
就简单多了。不确定什么发生了,但这似乎回答了错误的问题。编辑答案
var listOfLists = new List<List<int>>
{
new List<int> {1, 2, 3, 4},
new List<int> {5, 6, 7, 8},
new List<int> {9, 10}
};
IEnumerable<int> combined = new List<int>();
combined = listOfLists.Aggregate(combined, (current, list) => current.Concat(list)).ToList();
var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });
var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));
var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };
var combined = new []{ list1, list2 }.SelectMany(x => x);
public static class CollectionExtensions
{
public static void Add<T>(this ICollection<T> collection, IEnumerable<T> items)
{
foreach (var item in items) collection.Add(item);
}
}
var combined = new List<int> { list1, list2, 7, 8 };