C# Permutation of an array of arraylists?

后端 未结 13 821
难免孤独
难免孤独 2020-11-27 18:10

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)

         


        
相关标签:
13条回答
  • 2020-11-27 18:46

    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));
    }
    
    0 讨论(0)
  • 2020-11-27 18:47

    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;
    }
    
    0 讨论(0)
  • 2020-11-27 18:55
    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 讨论(0)
  • 2020-11-27 18:56

    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)));
        }
    
    0 讨论(0)
  • 2020-11-27 18:57

    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;
        }
    
    0 讨论(0)
  • 2020-11-27 18:59

    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

    0 讨论(0)
提交回复
热议问题