简体   繁体   中英

Get an enumerable of all sub lists of an existing list

I have a List<T> and I want to obtain all possible sub lists, eg:

[A, B, C, D, E] => [[A], [A, B], [A, B, C], [A, B, C, D], [A, B, C, D, E]]

Is there an easy way to do obtain this new enumerable with LINQ to Objects?

EDIT 1: Note that I only want "prefix lists", not all possible permutations (ie, the shown example result is already complete).

EDIT 2: Note that I want to maintain the order of the elements as well.

EDIT 3: Is there a way to obtain the enumerables in O(n) instead of O(n²), ie, by iterating over the source only once instead of multiple times and returning some kind of view on the data instead of a new list each time?

A very naive extension method:

public static class Extensions
{
    public static IEnumerable<IEnumerable<T>> GetOrderedSubEnumerables<T>(
                                              this IEnumerable<T> collection)
    {
        var builder = new List<T>();
        foreach (var element in collection)
        {
            builder.Add(element);
            yield return builder;
        }
    }
}

Use:

void Main()
{
    var list = new List<string> { "A", "B", "C", "D", "E" };
    Console.WriteLine(list.GetOrderedSubEnumerables());
}

Result:

排列

Note this will return views of your data as you iterate the collection. But eventually, if you need to consume each permutation separately, you'll need to copy each List<T> over before yielding it back. In that case, this should do it:

public static class Extensions
{
    public static IEnumerable<IEnumerable<T>> GetOrderedSubEnumerables<T>(
                                              this IEnumerable<T> collection)
    {
        var builder = new List<T>();
        foreach (var element in collection)
        {
            builder.Add(element);
            var local = new List<T>(builder);
            yield return local;
        }
    }
}

Yes you are right, your requirement is such a small subset of permutations that is has nothing to do with permutations anymore. So here my suggestion:

var result = Enumerable.Range(1, list.Count).
                Select(i => list.Take(i).ToList()).
                ToList();

You could iterate over a range of the number of items in your list and select the sublist like so:

var list = new List<string> { "A", "B", "C", "D", "E"};

var query =
    from i in Enumerable.Range(1, list.Count)
    select list.Take(i);

Keep in mind that if your data is not in a List<T> Count might be expensive. Also keep in mind that this iterates over your data more than once.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM