views:

1575

answers:

6

I've a List of this type List> that contains this

List<int> A = new List<int> {1, 2, 3, 4, 5};
List<int> B = new List<int> {0, 1};
List<int> C = new List<int> {6};
List<int> X = new List<int> {....,....};

I want to have all combinations like this

1-0-6
1-1-6
2-0-6
2-1-6
3-0-6

and so on.

According to you is This possibile to resolve using Linq?

+11  A: 

If the number of dimensions is fixed, this is simply SelectMany:

var qry = from a in A
          from b in B
          from c in C
          select new {A=a,B=b,C=c};

However, if the number of dimensions is controlled by the data, you need to use recursion:

static void Main() {
    List<List<int>> outerList = new List<List<int>>
    {   new List<int>(){1, 2, 3, 4, 5},
        new List<int>(){0, 1},
        new List<int>(){6,3},
        new List<int>(){1,3,5}
    };
    int[] result = new int[outerList.Count];
    Recurse(result, 0, outerList);
}
static void Recurse<TList>(int[] selected, int index,
    IEnumerable<TList> remaining) where TList : IEnumerable<int> {
    IEnumerable<int> nextList = remaining.FirstOrDefault();
    if (nextList == null) {
        StringBuilder sb = new StringBuilder();
        foreach (int i in selected) {
            sb.Append(i).Append(',');
        }
        if (sb.Length > 0) sb.Length--;
        Console.WriteLine(sb);
    } else {
        foreach (int i in nextList) {
            selected[index] = i;
            Recurse(selected, index + 1, remaining.Skip(1));
        }
    }
}
Marc Gravell
+1 Great solution.
spoulson
I managed it in a different manner that may be more readable depending on your viewpoint. What do you think?
Garry Shutler
+14  A: 

It's quite similar to this answer I gave to another question:

var combinations = from a in A
                   from b in B
                   from c in C
                   orderby a, b, c
                   select new List<int> { a, b, c };

var x = combinations.ToList();

For a variable number of inputs, now with added generics:

var x = AllCombinationsOf(A, B, C);

public static List<List<T>> AllCombinationsOf<T>(params List<T>[] sets)
{
    // need array bounds checking etc for production
    var combinations = new List<List<T>>();

    // prime the data
    foreach (var value in sets[0])
        combinations.Add(new List<T> { value });

    foreach (var set in sets.Skip(1))
        combinations = AddExtraSet(combinations, set);

    return combinations;
}

private static List<List<T>> AddExtraSet<T>
     (List<List<T>> combinations, List<T> set)
{
    var newCombinations = from value in set
                          from combination in combinations
                          select new List<T>(combination) { value };

    return newCombinations.ToList();
}
Garry Shutler
I don't think that works... I believe (from the X) that the OP means that the number of items in the list (and thus the number of dimensions) is dynamic
Marc Gravell
Hmmm, it's still possible based on my other references answer, you could just take a paramarray of sets and build it up. I'll ask for clarification in a comment.
Garry Shutler
I see you beat me to doing just that!
Garry Shutler
Yes guys the number of items is dynamic!
Giomuti
I see - you repeatedly cross 2 lists at a time in the loop - cute.
Marc Gravell
How Can I modify the function "AllCombinationsOf" to pass all the list and only list<object>?
Giomuti
AllCombinationsOf will take any number of lists (due to the params) argument, so long as those lists contain the same type (in this case int). So you could call AllCombinationsOf(List<Car>, List<Car>, List<Car>, List<Car>) without changing any code.
Garry Shutler
I've tried, it functions. But I need to pass to the function the entire list not only single elements!
Giomuti
I've understood but i want to pass the entire List<List<Object>>
Giomuti
I don't understand. You want to pass it the list of combinations in order to create a list of combinations?
Garry Shutler
Sorry for my english, I'm Italian.I' ve solved. This example maybe could help you!var A = new List<int>() { 1, 2, 3, 4, 5 };var B = new List<int>() { 1, 3, 5 };List<List<int>> L = new List<List<int>>();L.Add(A);L.Add(B);var X = Combinations.AllCombinationsOf(L.ToArray());Thanks very much.
Giomuti
If that's how you need to use it you could change the method to this signature: AllCombinationsOf<T>(List<List<T>> sets)I think it would still work without any other changes to the code. Otherwise what you've done will work, yes.
Garry Shutler
The biggest problem I can see with this approach is the number of allocations. With the array version, you don't have this - just the one array. It would be easy to pass in an Action<T[]> to enact on combinations...
Marc Gravell
How Can I solve this problem?
Giomuti
It is true, I was thinking about it last night. I'll have a think about it. However, it's currently readable (to me) and produces the correct result. So (potentially) obfusticating it in the name of performance may be a waste of time if it works sufficiently well.
Garry Shutler
I've to use it in a large project and I need performance!
Giomuti
Hi,I need to verify, during combination, if a value is greater than other. What do I have to do?Thanks very much!!!
Giomuti
@Marc +1 for "cute"
Dustin Fineout
A: 

Hi guys, Thanks for your answers. The number of dimensions is not fixed, could be a variable number.

Thanks.

Giomuti
As a note you should use comments for this sort of thing and update the question accordingly,
Garry Shutler
You might find you'll collect down votes for doing this as well.
Garry Shutler
A: 

I wanna ask you this:

If I have a List < List < Object > > where Object is a Class like this:

Class Object = new Class();
Object.X = ...;
Object.Y = ...;

and so on

How can I get combinations of this List? I wanna have this combinations in a Result List!

Giomuti
serious?! make it generic!
Andreas Niedermair
See the extension to my answer
Garry Shutler
A: 

Hi,

I've accepted this solution:

var x = AllCombinationsOf(A, B, C);

public static List> AllCombinationsOf(params List[] sets) { // need array bounds checking etc for production var combinations = new List>();

// prime the data
foreach (var value in sets[0])
    combinations.Add(new List<T> { value });

foreach (var set in sets.Skip(1))
    combinations = AddExtraSet(combinations, set);

return combinations;

}

private static List> AddExtraSet (List> combinations, List set) { var newCombinations = from value in set from combination in combinations select new List(combination) { value };

return newCombinations.ToList();

}

Now I need to verify, during combination, that a value of the class if greater than another. How Can I do this?

Thanks!

Giomuti
A: 

Hi guys,

How can I use this function in a multhreaded system?



public static List> AllCombinationsOf(params List[] sets) { // need array bounds checking etc for production var combinations = new List>();

// prime the data
foreach (var value in sets[0])
    combinations.Add(new List<T> { value });

foreach (var set in sets.Skip(1))
    combinations = AddExtraSet(combinations, set);

return combinations;

}

Giomuti