-1

I have those functions

    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> items, int count)
    {
        int i = 0;
        foreach (var item in items)
        {
            if (count == 1)
                yield return new T[] { item };
            else
            {
                foreach (var result in GetPermutations(items.Skip(i + 1), count - 1))
                    yield return new T[] { item }.Concat(result);
            }

            ++i;
        }
    }

    public static List<List<int>> GetAllValidCombinations(List<int> items)
    {
        var finalList = new List<List<int>>();
        switch (items.Count)
        {
            case 1:
                finalList.Add(items);
                break;
            case 3:
                finalList.AddRange(GetPermutations(items, 2));
                finalList.AddRange((List<List<int>>)GetPermutations(items, 3));
                break;
        }
        return finalList;
    }

and i want to get an List<List> from GetAllValidCombinations.

In the case 3 of GetAllValidCombinationsin the first line im getting: Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable>' to 'System.Collections.Generic.IEnumerable<System.Collections.Generic.List>'

and if i try the second line im getting error Specified cast is not valid

How i can do this cast in one line?

CDrosos
  • 2,418
  • 4
  • 26
  • 49

2 Answers2

2

AddRange expects an IEnumerable of Lists, but you have given it an IEnumerable of IEnumerables. Those IEnumerable could be anything, not necessarily lists, right? They could be sets or arrays or some other type that I wrote, that just happens to implement IEnumerable<T>... This is the reason why the compiler gives you the error.

And as you have written GetPermutations, we can see that they are actually arrays of T! So you are trying to add a bunch of arrays to a list of lists! That doesn't make much sense, does it?

Fortunately, ToList converts any IEnumerable to a List. You should apply this method to each IEnumerable nested inside the outer IEnumerable using Select:

var enumerableOfEnumerables = GetPermutations(items, 2);
finalList.AddRange(enumerableOfEnumerables.Select(x => x.ToList()));
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • You are right, i knew that what i was doing doesn't make sense without some casting but i wasn't able to figure out an one line cast for some reason, thanks – CDrosos Aug 18 '20 at 02:21
2

Sweepers answer is on the money, also you could refactor it a little by only using lists in the inner collection and making it completely generic.

public static IEnumerable<List<T>> GetPermutations<T>(List<T> items, int count)
{
   for (var index = 0; index < items.Count; index++)
      if (count == 1)
         yield return new List<T> { items[index] };
      else
         foreach (var result in GetPermutations(items.Skip(index + 1).ToList(), count - 1))
            yield return new List<T> { items[index] }
               .Concat(result)
               .ToList();
}

public static IEnumerable<List<T>> GetAllValidCombinations<T>(List<T> items)
{
   if (items.Count == 1)
       return new List<List<T>> {items};

   if (items.Count == 3)
      return GetPermutations(items, 2)
         .Concat(GetPermutations(items, 3));

   return Enumerable.Empty<List<T>>();
}

Usage

var results = GetAllValidCombinations(new List<int>() {1, 2, 3});

foreach (var result in results)
   Console.WriteLine(string.Join(",",result));

Output

1,2
1,3
2,3
1,2,3

Full Demo Here

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • Hi @CDrosos are you saying that it doesn't behave as expected, or there is an error ? – TheGeneral Aug 18 '20 at 02:29
  • i want GetPermutations(items, 2) to provide a List and GetPermutations(items, 3) to provide another List and both of them to be on another List that GetAllValidCombinations will return. With your implementation i think the returned list will have only one list – CDrosos Aug 18 '20 at 02:33
  • @CDrosos ahh yes i see what you are saying – TheGeneral Aug 18 '20 at 02:35
  • @CDrosos however it does as you would expect. Its joining the 2 collections of collections and returning them in a collection of collections. which is the same as creating a collection and 2 AddRanges and returning the result – TheGeneral Aug 18 '20 at 02:40
  • but your implementation will return GetAllValidCombinations(somethin).Count == 1 while i want GetAllValidCombinations(somethin).Count == 2. i want the GetPermutations results in seperated lists – CDrosos Aug 18 '20 at 02:44
  • @CDrosos test https://dotnetfiddle.net/ldLBuR, is this not doing what you want? – TheGeneral Aug 18 '20 at 02:52
  • Nice site i didn't know that. Yes your code indeed returns what i want. although i cant understand how for now. May i ask something else. is your implementation faster than Sweeper's answer. My code will do many calculations and i would like the faster approach – CDrosos Aug 18 '20 at 03:02
  • @CDrosos they would be almost identical in allocations and speed from what i can tell – TheGeneral Aug 18 '20 at 03:05