11

I have an ArrayList[] myList and I am trying to create a list of all the permutations of the values in the arrays.

EXAMPLE: (all values are strings)

myList[0] = { "1", "5", "3", "9" };
myList[1] = { "2", "3" };
myList[2] = { "93" };

The count of myList can be varied so its length is not known beforehand.

I would like to be able to generate a list of all the permutations similar to the following (but with some additional formatting).

1 2 93
1 3 93
5 2 93
5 3 93
3 2 93
3 3 93
9 2 93
9 3 93

Does this make sense of what I am trying to accomplish? I can't seem to come up with a good method for doing this, (if any).

Edit:
I am not sure if recursion would interfere with my desire to format the output in my own manner. Sorry I did not mention before what my formatting was.

I want to end up building a string[] array of all the combinations that follows the format like below:

for the "1 2 93" permutation

I want the output to be "val0=1;val1=2;val2=93;"

I will experiment with recursion for now. Thank you DrJokepu

Quintin Robinson
  • 81,193
  • 14
  • 123
  • 132
  • I don't have time at the moment to give a detailed answer, but think about doing it with recursion. – Tamas Czinege Apr 02 '09 at 17:09
  • I made an addition to my answer to comply with your requirement to be able to do your own formatting. – AaronLS Apr 02 '09 at 17:41
  • 1
    This has nothing to do with permutation. You just want all the combinations. – Guffa Apr 02 '09 at 17:43
  • @Guffa": That's the kind of correction that warrants an edit. But not by me, since I'm not confident enough for it. – Brian Apr 02 '09 at 18:11
  • 1
    Technically you are asking for the Cartesian Product, not the Permutation or Combination. – jamie Dec 30 '11 at 09:25
  • possible duplicate of [Generating all Possible Combinations](http://stackoverflow.com/questions/3093622/generating-all-possible-combinations) – Oliver Feb 08 '12 at 11:12

13 Answers13

18

I'm surprised nobody posted the LINQ solution.

from val0 in new []{ "1", "5", "3", "9" }
from val1 in new []{ "2", "3" }
from val2 in new []{ "93" }
select String.Format("val0={0};val1={1};val2={2}", val0, val1, val2)
Josh
  • 68,005
  • 14
  • 144
  • 156
14

Recursive solution

    static List<string> foo(int a, List<Array> x)
    {
        List<string> retval= new List<string>();
        if (a == x.Count)
        {
            retval.Add("");
            return retval;
        }
        foreach (Object y in x[a])
        {
            foreach (string x2 in foo(a + 1, x))
            {
                retval.Add(y.ToString() + " " + x2.ToString());
            }

        }
        return retval;
    }
    static void Main(string[] args)
    {
        List<Array> myList = new List<Array>();
        myList.Add(new string[0]);
        myList.Add(new string[0]);
        myList.Add(new string[0]);
        myList[0] = new string[]{ "1", "5", "3", "9" };
        myList[1] = new string[] { "2", "3" };
        myList[2] = new string[] { "93" };
        foreach (string x in foo(0, myList))
        {
            Console.WriteLine(x);
        }

        Console.ReadKey();
    }

Note that it would be pretty easy to return a list or array instead of a string by changing the return to be a list of lists of strings and changing the retval.add call to work with a list instead of using concatenation.

How it works:

This is a classic recursive algorithm. The base case is foo(myList.Count, myList), which returns a List containing one element, the empty string. The permutation of a list of n string arrays s1, s2, ..., sN is equal to every member of sA1 prefixed to the permutation of n-1 string arrays, s2, ..., sN. The base case is just there to provide something for each element of sN to be concatenated to.

Brian
  • 25,523
  • 18
  • 82
  • 173
5

I recently ran across a similar problem in a project of mine and stumbled on this question. I needed a non-recursive solution that could work with lists of arbitrary objects. Here's what I came up with. Basically I'm forming a list of enumerators for each of the sub-lists and incrementing them iteratively.

public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<IEnumerable<T>> lists)
{
    // Check against an empty list.
    if (!lists.Any())
    {
        yield break;
    }

    // Create a list of iterators into each of the sub-lists.
    List<IEnumerator<T>> iterators = new List<IEnumerator<T>>();
    foreach (var list in lists)
    {
        var it = list.GetEnumerator();
        // Ensure empty sub-lists are excluded.
        if (!it.MoveNext())
        {
            continue;
        }
        iterators.Add(it);
    }

    bool done = false;
    while (!done)
    {
        // Return the current state of all the iterator, this permutation.
        yield return from it in iterators select it.Current;

        // Move to the next permutation.
        bool recurse = false;
        var mainIt = iterators.GetEnumerator();
        mainIt.MoveNext(); // Move to the first, succeeds; the main list is not empty.
        do
        {
            recurse = false;
            var subIt = mainIt.Current;
            if (!subIt.MoveNext())
            {
                subIt.Reset(); // Note the sub-list must be a reset-able IEnumerable!
                subIt.MoveNext(); // Move to the first, succeeds; each sub-list is not empty.

                if (!mainIt.MoveNext())
                {
                    done = true;
                }
                else
                {
                    recurse = true;
                }
            }
        }
        while (recurse);
    }
}
Chadwick
  • 944
  • 12
  • 15
  • This method works really well for my purpose (millions to trillions of permutations of numerous lists with numerous objects). I checked the validity of the results by applying Distinct() and Jon Skeet's DistinctBy(). I added the this keyword to this method to make it an extension method. – user654123 Sep 05 '13 at 14:00
3

You could use factoradics to generate the enumeration of permutations. Try this article on MSDN for an implementation in C#.

Neil Williams
  • 12,318
  • 4
  • 43
  • 40
2

This will work no matter how many arrays you add to your myList:

        static void Main(string[] args)
        {
            string[][] myList = new string[3][];
            myList[0] = new string[] { "1", "5", "3", "9" };
            myList[1] = new string[] { "2", "3" };
            myList[2] = new string[] { "93" };

            List<string> permutations = new List<string>(myList[0]);

            for (int i = 1; i < myList.Length; ++i)
            {
                permutations = RecursiveAppend(permutations, myList[i]);
            }

            //at this point the permutations variable contains all permutations

        }

        static List<string> RecursiveAppend(List<string> priorPermutations, string[] additions)
        {
            List<string> newPermutationsResult = new List<string>();
            foreach (string priorPermutation in priorPermutations)
            {
                foreach (string addition in additions)
                {
                    newPermutationsResult.Add(priorPermutation + ":" + addition);
                }
            }
            return newPermutationsResult;
        }

Note that it's not really recursive. Probably a misleading function name.

Here is a version that adheres to your new requirements. Note the section where I output to console, this is where you can do your own formatting:

static void Main(string[] args)
        {
            string[][] myList = new string[3][];
            myList[0] = new string[] { "1", "5", "3", "9" };
            myList[1] = new string[] { "2", "3" };
            myList[2] = new string[] { "93" };

            List<List<string>> permutations = new List<List<string>>();

            foreach (string init in myList[0])
            {
                List<string> temp = new List<string>();
                temp.Add(init);
                permutations.Add(temp);
            }

            for (int i = 1; i < myList.Length; ++i)
            {
                permutations = RecursiveAppend(permutations, myList[i]);
            }

            //at this point the permutations variable contains all permutations

            foreach (List<string> list in permutations)
            {
                foreach (string item in list)
                {
                    Console.Write(item + ":");
                }
                Console.WriteLine();
            }

        }

        static List<List<string>> RecursiveAppend(List<List<string>> priorPermutations, string[] additions)
        {
            List<List<string>> newPermutationsResult = new List<List<string>>();
            foreach (List<string> priorPermutation in priorPermutations)
            {
                foreach (string addition in additions)
                {
                    List<string> priorWithAddition = new List<string>(priorPermutation);
                    priorWithAddition.Add(addition);
                    newPermutationsResult.Add(priorWithAddition);
                }
            }
            return newPermutationsResult;
        }
AaronLS
  • 37,329
  • 20
  • 143
  • 202
2

What you are asking for is called the Cartesian Product. Once you know what its called, there are several similar questions on Stack Overflow. They all seem to end up pointing to an answer which ended up written as a blog post:

http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx

jamie
  • 2,963
  • 1
  • 26
  • 27
1

Non-recursive solution:

foreach (String s1 in array1) {
    foreach (String s2 in array2) {
        foreach (String s3 in array3) {
            String result = s1 + " " + s2 + " " + s3;
            //do something with the result
        }
    }
}

Recursive solution:

private ArrayList<String> permute(ArrayList<ArrayList<String>> ar, int startIndex) {
    if (ar.Count == 1) {
        foreach(String s in ar.Value(0)) {
            ar.Value(0) = "val" + startIndex + "=" + ar.Value(0);
        return ar.Value(0);
    }
    ArrayList<String> ret = new ArrayList<String>();
    ArrayList<String> tmp1 ar.Value(0);
    ar.remove(0);
    ArrayList<String> tmp2 = permute(ar, startIndex+1);
    foreach (String s in tmp1) {
        foreach (String s2 in tmp2) {
            ret.Add("val" + startIndex + "=" + s + " " + s2);
        }
    }
    return ret;
}
Elie
  • 13,693
  • 23
  • 74
  • 128
  • true. I answered specific to the question, not in general. I guess that leaves recursion. – Elie Apr 02 '09 at 17:17
  • Based on the TaRDy's statement "The count of myList can be varied so its length is not known beforehand.", this doesn't really solve his problem. But, it would work well for count=3. – itsmatt Apr 02 '09 at 17:17
  • Right, the nested loop solution is trivial. I'm trying to come up with a recursive solution, as the algorithm could be seen as a tree.. – Wadih M. Apr 02 '09 at 17:19
  • I see you've added a recursive version :) – Wadih M. Apr 02 '09 at 18:30
0

Here is a generic recursive function that I wrote (and an overload that may be convenient to call):

Public Shared Function GetCombinationsFromIEnumerables(ByRef chain() As Object, ByRef IEnumerables As IEnumerable(Of IEnumerable(Of Object))) As List(Of Object())
    Dim Combinations As New List(Of Object())
    If IEnumerables.Any Then
        For Each v In IEnumerables.First
            Combinations.AddRange(GetCombinationsFromIEnumerables(chain.Concat(New Object() {v}).ToArray, IEnumerables.Skip(1)).ToArray)
        Next
    Else
        Combinations.Add(chain)
    End If
    Return Combinations
End Function

Public Shared Function GetCombinationsFromIEnumerables(ByVal ParamArray IEnumerables() As IEnumerable(Of Object)) As List(Of Object())
    Return GetCombinationsFromIEnumerables(chain:=New Object() {}, IEnumerables:=IEnumerables.AsEnumerable)
End Function

And the equivalent in C#:

public static List<object[]> GetCombinationsFromIEnumerables(ref object[] chain, ref IEnumerable<IEnumerable<object>> IEnumerables)
{
List<object[]> Combinations = new List<object[]>();
if (IEnumerables.Any) {
    foreach ( v in IEnumerables.First) {
        Combinations.AddRange(GetCombinationsFromIEnumerables(chain.Concat(new object[] { v }).ToArray, IEnumerables.Skip(1)).ToArray);
    }
} else {
    Combinations.Add(chain);
}
return Combinations;
}

public static List<object[]> GetCombinationsFromIEnumerables(params IEnumerable<object>[] IEnumerables)
{
return GetCombinationsFromIEnumerables(chain = new object[], IEnumerables = IEnumerables.AsEnumerable);
}

Easy to use:

Dim list1 = New String() {"hello", "bonjour", "hallo", "hola"}
Dim list2 = New String() {"Erwin", "Larry", "Bill"}
Dim list3 = New String() {"!", ".."}
Dim result = MyLib.GetCombinationsFromIEnumerables(list1, list2, list3)
For Each r In result
    Debug.Print(String.Join(" "c, r))
Next

or in C#:

object list1 = new string[] {"hello","bonjour","hallo","hola"};
object list2 = new string[] {"Erwin", "Larry", "Bill"};
object list3 = new string[] {"!",".."};
object result = MyLib.GetCombinationsFromIEnumerables(list1, list2, list3);
foreach (r in result) {
Debug.Print(string.Join(' ', r));
}
Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
0
private static void GetP(List<List<string>> conditions, List<List<string>> combinations, List<string> conditionCombo, List<string> previousT, int selectCnt)
{
    for (int i = 0; i < conditions.Count(); i++)
    {
        List<string> oneField = conditions[i];
        for (int k = 0; k < oneField.Count(); k++)
        {
            List<string> t = new List<string>(conditionCombo);
            t.AddRange(previousT);
            t.Add(oneField[k]);

            if (selectCnt == t.Count )
            {
                combinations.Add(t);
                continue;
            }
            GetP(conditions.GetRange(i + 1, conditions.Count - 1 - i), combinations, conditionCombo, t, selectCnt);
        }

    }
}

List<List<string>> a = new List<List<string>>();
a.Add(new List<string> { "1", "5", "3", "9" });
a.Add(new List<string> { "2", "3" });
a.Add(new List<string> { "93" });
List<List<string>> result = new List<List<string>>();
GetP(a, result, new List<string>(), new List<string>(), a.Count);

Another recursive function.

paddywide
  • 15
  • 8
0

Here is a version which uses very little code, and is entirely declarative

    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> collection) where T : IComparable
    {
        if (!collection.Any())
        {
            return new List<IEnumerable<T>>() {Enumerable.Empty<T>() };
        }
        var sequence = collection.OrderBy(s => s).ToArray();
        return sequence.SelectMany(s => GetPermutations(sequence.Where(s2 => !s2.Equals(s))).Select(sq => (new T[] {s}).Concat(sq)));
    }
J Pullar
  • 1,915
  • 2
  • 18
  • 30
0
class Program
{
    static void Main(string[] args)
    {
        var listofInts = new List<List<int>>(3);
        listofInts.Add(new List<int>{1, 2, 3});
        listofInts.Add(new List<int> { 4,5,6 });
        listofInts.Add(new List<int> { 7,8,9,10 });

        var temp = CrossJoinLists(listofInts);
        foreach (var l in temp)
        {
            foreach (var i in l)
                Console.Write(i + ",");
            Console.WriteLine();
        }
    }

    private static IEnumerable<List<T>> CrossJoinLists<T>(IEnumerable<List<T>> listofObjects)
    {
        var result = from obj in listofObjects.First()
                     select new List<T> {obj};

        for (var i = 1; i < listofObjects.Count(); i++)
        {
            var iLocal = i;
            result = from obj  in result
                     from obj2 in listofObjects.ElementAt(iLocal)
                     select new List<T>(obj){ obj2 };
        }

        return result;
    }
}
0

Here's a non-recursive, non-Linq solution. I can't help feeling like I could have less looping and calculate the positions with division and modulo, but can't quite wrap my head around that.

static void Main(string[] args)
    {
        //build test list
        List<string[]> myList = new List<string[]>();
        myList.Add(new string[0]);
        myList.Add(new string[0]);
        myList.Add(new string[0]);
        myList[0] = new string[] { "1", "2", "3"};
        myList[1] = new string[] { "4", "5" };
        myList[2] = new string[] { "7", "8", "9" };

        object[][] xProds = GetProducts(myList.ToArray());
        foreach(object[] os in xProds)
        {
            foreach(object o in os)
            {
                Console.Write(o.ToString() + " ");
            }
            Console.WriteLine();
        }
        Console.ReadKey();
    }

    static object[][] GetProducts(object[][] jaggedArray){
        int numLists = jaggedArray.Length;
        int nProducts = 1;
        foreach (object[] oArray in jaggedArray)
        {
            nProducts *= oArray.Length;
        }
        object[][] productAry = new object[nProducts][];//holds the results
        int[] listIdxArray = new int[numLists];
        listIdxArray.Initialize();
        int listPtr = 0;//point to current list

        for(int rowcounter = 0; rowcounter < nProducts; rowcounter++)
        {
            //create a result row
            object[] prodRow = new object[numLists];
            //get values for each column
            for(int i=0;i<numLists;i++)
            {
                prodRow[i] = jaggedArray[i][listIdxArray[i]];
            }
            productAry[rowcounter] = prodRow;
            //move the list pointer
            //possible states
            // 1) in a list, has room to move down
            // 2) at bottom of list, can move to next list
            // 3) at bottom of list, no more lists left
            //in a list, can move down
            if (listIdxArray[listPtr] < (jaggedArray[listPtr].Length - 1))
            {
                listIdxArray[listPtr]++;
            }
            else
            {
                //can move to next column?
                //move the pointer over until we find a list, or run out of room
                while (listPtr < numLists && listIdxArray[listPtr] >= (jaggedArray[listPtr].Length - 1))
                {
                    listPtr++;
                }
                if (listPtr < listIdxArray.Length && listIdxArray[listPtr] < (jaggedArray[listPtr].Length - 1))
                {
                    //zero out the previous stuff
                    for (int k = 0; k < listPtr; k++)
                    {
                        listIdxArray[k] = 0;
                    }
                    listIdxArray[listPtr]++;
                    listPtr = 0;
                }
            }
        }
        return productAry;
    }
Aerik
  • 2,307
  • 1
  • 27
  • 39
0

One of the problems I encountred when I was doing this for a very large amount of codes was that with the example brian was given I actually run out of memory. To solve this I used following code.

static void foo(string s, List<Array> x, int a)
    {
        if (a == x.Count)
        {
            // output here
            Console.WriteLine(s);
        }
        else
        {
            foreach (object y in x[a])
            {
                foo(s + y.ToString(), x, a + 1);
            }
        }
    }

static void Main(string[] args)
    {
        List<Array> a = new List<Array>();
        a.Add(new string[0]);
        a.Add(new string[0]);
        a.Add(new string[0]);
        a[0] = new string[] { "T", "Z" };
        a[1] = new string[] { "N", "Z" };
        a[2] = new string[] { "3", "2", "Z" };

        foo("", a, 0);
        Console.Read();
    }
pieter.lowie
  • 108
  • 11