优雅的方式结合多个元素集合?

Don*_*nut 80 c# linq generics collections

假设我有任意数量的集合,每个集合包含相同类型的对象(例如,List<int> fooList<int> bar).如果这些集合本身就是一个集合(例如,类型List<List<int>>,我可以使用SelectMany它们将它们全部合并到一个集合中.

但是,如果这些集合不在同一个集合中,那么我的印象是我必须编写这样的方法:

public static IEnumerable<T> Combine<T>(params ICollection<T>[] toCombine)
{
   return toCombine.SelectMany(x => x);
}
Run Code Online (Sandbox Code Playgroud)

然后我会这样称呼:

var combined = Combine(foo, bar);
Run Code Online (Sandbox Code Playgroud)

是否有一种干净,优雅的方式来组合(任意数量)集合而无需编写Combine如上所述的实用方法?看起来很简单,应该有一种方法在LINQ中做到,但也许不是.

Dom*_*nic 88

我想你可能在寻找LINQ的.Concat()

var combined = foo.Concat(bar).Concat(foobar).Concat(...);
Run Code Online (Sandbox Code Playgroud)

或者,.Union()将删除重复的元素.

  • 谢谢; 我最初没有这样做的唯一原因是(对我来说)你需要处理的收藏品越多越好.然而,这具有使用现有LINQ功能的好处,未来的开发人员可能已经熟悉这些功能. (2认同)
  • 感谢`.Union()` 提示。请记住,您**将需要**在您的自定义类型上实现 IComparer,以防万一。 (2认同)

naw*_*fal 24

对我来说,Concat作为一种扩展方法在我的代码中并不是很优雅,因为我有多个大序列要连接.这只是一个codde缩进/格式化问题,而且非常个人化.

当然看起来像这样:

var list = list1.Concat(list2).Concat(list3);
Run Code Online (Sandbox Code Playgroud)

读起来不太可读:

var list = list1.Select(x = > x)
   .Concat(list2.Where(x => true)
   .Concat(list3.OrderBy(x => x));
Run Code Online (Sandbox Code Playgroud)

或者当它看起来像:

return Normalize(list1, a, b)
    .Concat(Normalize(list2, b, c))
       .Concat(Normalize(list3, c, d));
Run Code Online (Sandbox Code Playgroud)

或者你喜欢的格式是什么.随着更复杂的concats,事情变得更糟.我上述风格认知失调的原因是第一个序列位于Concat方法之外,而后续序列位于内部.我更喜欢Concat直接调用静态方法而不是扩展样式:

var list = Enumerable.Concat(list1.Select(x => x),
                             list2.Where(x => true));
Run Code Online (Sandbox Code Playgroud)

对于更多序列的concats,我使用与OP中相同的静态方法:

public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sequences)
{
    return sequences.SelectMany(x => x);
}
Run Code Online (Sandbox Code Playgroud)

所以我可以写:

return EnumerableEx.Concat
(
    list1.Select(x = > x),
    list2.Where(x => true),
    list3.OrderBy(x => x)
);
Run Code Online (Sandbox Code Playgroud)

看起来更好.考虑到我的序列看起来更干净,我必须写的额外的,否则多余的类名对我来说不是问题Concat.这不是C#6中的问题.你可以写:

return Concat(list1.Select(x = > x),
              list2.Where(x => true),
              list3.OrderBy(x => x));
Run Code Online (Sandbox Code Playgroud)

希望我们在C#中有列表连接运算符,类似于:

list1 @ list2 // F#
list1 ++ list2 // Scala
Run Code Online (Sandbox Code Playgroud)

那种方式更清洁.

  • 感谢您对编码风格的关注。这要优雅得多。 (4认同)
  • 我也喜欢这种格式-尽管为了清楚起见,我更喜欢先执行单个列表操作(例如`Where`,`OrderBy`),特别是如果它们比本示例复杂的话。 (2认同)

ast*_*sov 22

List<List<T>> 这是正确的"优雅"方式:

var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });
Run Code Online (Sandbox Code Playgroud)


jas*_*son 14

使用Enumerable.Concat如下:

var combined = foo.Concat(bar).Concat(baz)....;
Run Code Online (Sandbox Code Playgroud)


小智 7

你总是可以使用Aggregate和Concat结合...

        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();
Run Code Online (Sandbox Code Playgroud)


Res*_*uta 6

我看到的唯一方法是使用 Concat()

 var foo = new List<int> { 1, 2, 3 };
 var bar = new List<int> { 4, 5, 6 };
 var tor = new List<int> { 7, 8, 9 };

 var result = foo.Concat(bar).Concat(tor);
Run Code Online (Sandbox Code Playgroud)

但你应该决定什么是更好的:

var result = Combine(foo, bar, tor);
Run Code Online (Sandbox Code Playgroud)

要么

var result = foo.Concat(bar).Concat(tor);
Run Code Online (Sandbox Code Playgroud)

有一点,为什么Concat()会是更好的选择是,这将是另一个开发者更为明显.更具可读性和简单性.