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

发布于 2024-10-08 05:06:23 字数 613 浏览 8 评论 0 原文

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

但是,如果这些集合尚未位于同一个集合中,我的印象是我必须编写这样的方法:

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

然后我会这样调用:

var combined = Combine(foo, bar);

是否有一种干净、优雅的方式来组合(任意数量的)集合无需编写像上面的 Combine 这样的实用方法?看起来很简单,应该有一种方法可以在 LINQ 中实现这一点,但也许不是。

Say I have an arbitrary number of collections, each containing objects of the same type (for example, List<int> foo and List<int> bar). If these collections were themselves in a collection (e.g., of type List<List<int>>, I could use SelectMany to combine them all into one collection.

However, if these collections are not already in the same collection, it's my impression that I'd have to write a method like this:

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

Which I'd then call like this:

var combined = Combine(foo, bar);

Is there a clean, elegant way to combine (any number of) collections without having to write a utility method like Combine above? It seems simple enough that there should be a way to do it in LINQ, but perhaps not.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

硪扪都還晓 2024-10-15 05:06:24

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

var combined = foo.Concat(bar).Concat(foobar).Concat(...);

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

I think you might be looking for LINQ's .Concat()?

var combined = foo.Concat(bar).Concat(foobar).Concat(...);

Alternatively, .Union() will remove duplicate elements.

一杆小烟枪 2024-10-15 05:06:24

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

当然,它看起来像这样:

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 方法,而不是扩展样式:

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);
}

所以我可以写:

return EnumerableEx.Concat
(
    list1.Select(x = > x),
    list2.Where(x => true),
    list3.OrderBy(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

这样更干净。

To me Concat as an extension method is not very elegant in my code when I have multiple large sequences to concat. This is merely a codde indentation/formatting problem and something very personal.

Sure it looks good like this:

var list = list1.Concat(list2).Concat(list3);

Not so readable when it reads like:

var list = list1.Select(x = > x)
   .Concat(list2.Where(x => true)
   .Concat(list3.OrderBy(x => x));

Or when it looks like:

return Normalize(list1, a, b)
    .Concat(Normalize(list2, b, c))
       .Concat(Normalize(list3, c, d));

or whatever your preferred formatting is. Things get worse with more complex concats. The reason for my sort of cognitive dissonance with the above style is that the first sequence lie outside of the Concat method whereas the subsequent sequences lie inside. I rather prefer to call the static Concat method directly and not the extension style:

var list = Enumerable.Concat(list1.Select(x => x),
                             list2.Where(x => true));

For more number of concats of sequences I carry the same static method as in OP:

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

So I can write:

return EnumerableEx.Concat
(
    list1.Select(x = > x),
    list2.Where(x => true),
    list3.OrderBy(x => x)
);

Looks better. The extra, otherwise redundant, class name I have to write is not a problem for me considering my sequences look cleaner with the Concat call. It's less of a problem in C# 6. You can just write:

return Concat(list1.Select(x = > x),
              list2.Where(x => true),
              list3.OrderBy(x => x));

Wished we had list concatenation operators in C#, something like:

list1 @ list2 // F#
list1 ++ list2 // Scala

Much cleaner that way.

¢蛋碎的人ぎ生 2024-10-15 05:06:24

对于当您确实有一个集合的集合时的情况,即List>Enumerable.Aggregate是一个更将所有列表合并为一个的优雅方式:

var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });

For the case when you do have a collection of collections, i.e. a List<List<T>>, Enumerable.Aggregate is a more elegant way to combine all lists into one:

var combined = lists.Aggregate((acc, list) => { return acc.Concat(list); });
梨涡 2024-10-15 05:06:24

使用 Enumerable.Concat 如下所示:

var combined = foo.Concat(bar).Concat(baz)....;

Use Enumerable.Concat like so:

var combined = foo.Concat(bar).Concat(baz)....;
雨巷深深 2024-10-15 05:06:24

您始终可以将 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();

You could always use Aggregate combined with 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();
清君侧 2024-10-15 05:06:24

使用 Enumerable.Concat

var query = foo.Concat(bar);

Use Enumerable.Concat:

var query = foo.Concat(bar);
苍景流年 2024-10-15 05:06:24

我看到的唯一方法是使用 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);

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

var result = Combine(foo, bar, tor);

或者

var result = foo.Concat(bar).Concat(tor);

一点为什么 Concat() 将是一个更好的选择是,对于另一个开发人员来说,这会更加明显。更具可读性和简单性。

The only way I see is to use 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);

But you should decide what is better:

var result = Combine(foo, bar, tor);

or

var result = foo.Concat(bar).Concat(tor);

One point why Concat() will be a better choice is that it will be more obvious for another developer. More readable and simple.

初相遇 2024-10-15 05:06:24

您可以按如下方式使用 Union:

var combined=foo.Union(bar).Union(baz)...

不过,这会删除相同的元素,因此如果您有这些元素,您可能需要使用 Concat 来代替。

You can use Union as follows:

var combined=foo.Union(bar).Union(baz)...

This will remove identical elements, though, so if you have those, you might want to use Concat, instead.

无所的.畏惧 2024-10-15 05:06:24

对于任何 IEnumerable> ,您所需要的就是这个lists

var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));

这会将 lists 中的所有项目组合成一个 IEnumerable(包含重复项)。使用 Union 而不是 Concat 来删除重复项,如其他答案中所述。

All you need is this, for any IEnumerable<IEnumerable<T>> lists :

var combined = lists.Aggregate((l1, l2) => l1.Concat(l2));

This will combine all the items in lists into one IEnumerable<T> (with duplicates). Use Union instead of Concat to remove duplicates, as noted in the other answers.

瞳孔里扚悲伤 2024-10-15 05:06:24

使用集合初始值设定项的一些技术 -

假设这些列表:

var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };

带有数组初始值设定项的 SelectMany (对我来说不是那么优雅,但不依赖于任何辅助函数):

var combined = new []{ list1, list2 }.SelectMany(x => x);

为 Add 定义一个列表扩展允许 List 中的 IEnumerable 初始化器

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 };

A couple techniques using Collection Initializers --

assuming these lists:

var list1 = new List<int> { 1, 2, 3 };
var list2 = new List<int> { 4, 5, 6 };

SelectMany with an array initializer (not really that elegant to me, but doesn't rely on any helper function):

var combined = new []{ list1, list2 }.SelectMany(x => x);

Define a list extension for Add which allows IEnumerable<T> in the List<T> initializer:

public static class CollectionExtensions
{
    public static void Add<T>(this ICollection<T> collection, IEnumerable<T> items)
    {
        foreach (var item in items) collection.Add(item);
    }
}

Then you can create a new list containing the elements of the others like this (it also allows single items to be mixed in).

var combined = new List<int> { list1, list2, 7, 8 };
兰花执着 2024-10-15 05:06:24

鉴于您从一堆单独的集合开始,我认为您的解决方案相当优雅。您将必须做一些事情来将它们缝合在一起。

从语法上来说,从您的合并方法中创建一个扩展方法会更方便,这将使它可以在任何地方使用。

Given that you're starting with a bunch of separate collections, I think your solution is rather elegant. You're going to have to do something to stitch them together.

It would be more convenient syntactically to make an extension method out of your Combine method, which would make it available anywhere you go.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文