Skip to content

[API Proposal]: Add Enumerable.Concat & Flatten overloads #54220

Open

Description

@TonyValenti

Background and Motivation

When working with different APIs, often times it increases code readability to aggregate results and then linearize them. For example, I could write the code:

Command.NameInfo.OnlineAccounts = new List<OnlineAccount>();
Command.NameInfo.OnlineAccounts.AddRange(Input.WebAddresses.Select(x => CreateWebAddress(x)));
Command.NameInfo.OnlineAccounts.AddRange(Input.EmailAddresses.Select(x => CreateEmailAddress(x)));

or I could write:

Command.NameInfo.OnlineAccounts = new[] {
    Input.WebAddresses.Select(x => CreateWebAddress(x)),
    Input.EmailAddresses.Select(x => CreateEmailAddress(x))
}.Concat().ToList();

The second is much more clear and concise.

Proposed API

namespace System.Linq 
{
    public static class Enumerable 
    {
        public static IEnumerable<T> Concat<T>(this IEnumerable<TSource> first, IEnumerable<TSource> second);
+        public static IEnumerable<T> Concat<T>(params IEnumerable<T>[] sources);
+        public static IEnumerable<T> Concat<T>(this IEnumerable<IEnumerable<T>> sources);
    }
}

Usage Examples

var source = Enumerable.Range(0, 2);

Enumerable.Concat(source, source, source, source); // 0, 1, 0, 1, 0, 1, 0, 1
Enumerable.Repeat(source, 3).Concat(); // 0, 1, 0, 1, 0, 1

Alternative Designs

Just use SelectMany(x => x)

Risks

None other than System.Linq size concerns.

Activity

  1. added
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Jun 15, 2021
  2. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Jun 15, 2021
  3. eiriktsarpalis commented on Jun 15, 2021

    @eiriktsarpalis
    Member

    I'm assuming SelectMany() and Concat() are just alternative names for the same proposed method? Why not just stick with one? I personally would prefer exposing Concat() as an overload, since F# uses the same name for its equivalent method.

  4. added
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    and removed
    untriagedNew issue has not been triaged by the area owner
    on Jun 15, 2021
  5. added this to the 7.0.0 milestone on Jun 15, 2021
  6. svick commented on Jun 16, 2021

    @svick
    Member

    Note that another way to write this code is to use the existing overload of Concat:

    Command.NameInfo.OnlineAccounts = 
        Input.WebAddresses.Select(x => CreateWebAddress(x))
            .Concat(Input.EmailAddresses.Select(x => CreateEmailAddress(x)))
            .ToList();

    Or:

    Command.NameInfo.OnlineAccounts = Enumerable.Concat(
        Input.WebAddresses.Select(x => CreateWebAddress(x)),
        Input.EmailAddresses.Select(x => CreateEmailAddress(x))
    ).ToList();

    But you do have to choose between the fluent assymetric form and the non-fluent symmetric form. So I think the proposed overload of Concat would still be a good addition.

  7. eiriktsarpalis commented on Jun 16, 2021

    @eiriktsarpalis
    Member

    Agreed, @TonyValenti if you could update the OP following the API proposal template we can consider this proposal for .NET 7.

  8. removed
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Jun 25, 2021
  9. danielchalmers commented on Aug 12, 2021

    @danielchalmers
    Contributor

    I often make a Flatten<T>(this IEnumerable<T> l)=>l.SelectMany(x=>x) extension so I would love to see this in the BCL!

  10. eiriktsarpalis commented on Aug 13, 2021

    @eiriktsarpalis
    Member

    @danielchalmers please consider upvoting the original post, it provides a good signal on whether a particular proposal is popular!

  11. added
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    and removed
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    on Oct 14, 2021
  12. 20 remaining items

  13. changed the title [-][API Proposal]: Add Enumerable.Concat overloads for variadic arguments and nested enumerables[/-] [+][API Proposal]: Add Enumerable.Concat & Flatten overloads[/+] on Oct 21, 2021
  14. ghost added
    in-prThere is an active PR which will close this issue when it is merged
    on Nov 4, 2021
  15. added
    api-needs-workAPI needs work before it is approved, it is NOT ready for implementation
    and removed
    api-approvedAPI was approved in API review, it can be implemented
    on Nov 15, 2021
  16. eiriktsarpalis commented on Nov 15, 2021

    @eiriktsarpalis
    Member

    Changed to api-needs-work due to feedback in #61230. cc @stephentoub

  17. modified the milestones: 7.0.0, Future on Nov 15, 2021
  18. ghost removed
    in-prThere is an active PR which will close this issue when it is merged
    on Nov 15, 2021
  19. TahirAhmadov commented on Nov 27, 2021

    @TahirAhmadov

    @bartonjs did you consider the solution I proposed here ?

  20. LeaFrock commented on Mar 23, 2023

    @LeaFrock
    Contributor

    No progress for .NET 8? Does IQueryable block it?

  21. removed their assignment
    on Mar 27, 2023
  22. JBrown526 commented on Sep 17, 2024

    @JBrown526

    It would be nice to have a Flatten() or parameterless SelectMany() implementation at least, as the current usage of nestedCollections.SelectMany(x => x);` never seems particularly intuitive or meaningful for me

  23. julealgon commented on Sep 17, 2024

    @julealgon

    or I could write:

    Command.NameInfo.OnlineAccounts = new[] {
        Input.WebAddresses.Select(x => CreateWebAddress(x)),
        Input.EmailAddresses.Select(x => CreateEmailAddress(x))
    }.Concat().ToList();

    With collection literals and the spread operator, I assume this example would be completely nullified since you can just do:

    Command.NameInfo.OnlineAccounts = [
        ..Input.WebAddresses.Select(x => CreateWebAddress(x)),
        ..Input.EmailAddresses.Select(x => CreateEmailAddress(x))
    ];

    Or am I missing something?

  24. Thaina commented on Sep 18, 2025

    @Thaina

    I would like to add my voice to Flatten() or parameterless SelectMany() too. I think the old BCL was not support this because it lack contravariant feature? If so we now have contravariant it should be allowed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-needs-workAPI needs work before it is approved, it is NOT ready for implementationarea-System.Linq

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions