3

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

[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 (i.e., 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²), i.e., 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?

D.R.
  • 20,268
  • 21
  • 102
  • 205

3 Answers3

4

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:

Permutations

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;
        }
    }
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
0

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();
René Vogt
  • 43,056
  • 14
  • 77
  • 99
0

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.