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
)首先是为了清楚起见,特别是如果它们比这个例子更复杂的话。到目前为止,最好的解决方案是。@Oleg
SelectMany
更简单。你如何首先在这里获得
列表呢?这是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 };