Recursive algorithm to generate all combinations of elements in successive enumerables
If you need to flatten ordered enumerables, that is taking one element of each enumerable, in order, to flatten a combination, here is a quick solution in C# and VB.NET, accompanied with an example:
Code in VB.NET:
Private Shared Sub GetCombinationsRec(Of T)(sources As IList(Of IEnumerable(Of T)), chain As T(), index As Integer, combinations As ICollection(Of T())) For Each element As var In sources(index) chain(index) = element If index Is sources.Count - 1 Then Dim finalChain = New T(chain.Length - 1) {} chain.CopyTo(finalChain, 0) combinations.Add(finalChain) Else GetCombinationsRec(sources := sources, chain := chain, index := index + 1, combinations := combinations) End If Next End Sub Public Shared Function GetCombinations(Of T)(ParamArray enumerables As IEnumerable(Of T)()) As List(Of T()) Dim combinations = New List(Of T())(enumerables.Length) If enumerables.Length > 0 Then Dim chain = New T(enumerables.Length - 1) {} GetCombinationsRec(sources := enumerables, chain := chain, index := 0, combinations := combinations) End If Return combinations End Function
Code in C#.NET:
private static void GetCombinationsRec<T>(IList<IEnumerable<T>> sources, T[] chain, int index, ICollection<T[]> combinations) { foreach (var element in sources[index]) { chain[index] = element; if (index == sources.Count - 1) { var finalChain = new T[chain.Length]; chain.CopyTo(finalChain, 0); combinations.Add(finalChain); } else { GetCombinationsRec(sources: sources, chain: chain, index: index + 1, combinations: combinations); } } } public static List<T[]> GetCombinations<T>(params IEnumerable<T>[] enumerables) { var combinations = new List<T[]>(enumerables.Length); if (enumerables.Length > 0) { var chain = new T[enumerables.Length]; GetCombinationsRec(sources: enumerables, chain: chain, index: 0, combinations: combinations); } return combinations; }
Usage is simple:
Dim list1 = New String() {"hello", "bonjour", "hallo", "hola"} Dim list2 = New String() {"Erwin", "Larry", "Bill", "Steve"} Dim list3 = New String() {"!", ".."} Dim result = Utils.GetCombinations(list1, list2, list3) For Each r In result Debug.Print(String.Join(" "c, r)) Next
or in C#:
var list1 = new[] { "Hello", "Bonjour", "Hallo", "Hola" }; var list2 = new[] { "Erwin", "Larry", "Bill", "Steve" }; var list3 = new[] { "!", "..." }; var result = Utils.GetCombinations(list1, list2, list3); foreach (r in result) { Debug.Print(string.Join(" ", r)); }
As with any recursive function, memory usage can be exponential so make sure you know the number of target combinations is reasonable. Speed-wise, parallelizing this function is not worth it as we are just iterating over the elements.
I was unable to get the vb code to wrk
something about
Dim result = Utils.GetCombinations(list1, list2, list3)
It would error out here telling me to generate a stub please help
You have to declare the function as part of a public class named MyLib:
Public Class Utils
Public Shared Function GetCombinations(…)
End Function
End Class