namespace WhiteRabbit { using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; /// /// Converts e.g. pair of variants [[a, b, c], [d, e]] into all possible pairs: [[a, d], [a, e], [b, d], [b, e], [c, d], [c, e]] /// internal static class Flattener { // Slow universal implementation private static IEnumerable> FlattenAny(ImmutableStack phrase) { if (phrase.IsEmpty) { return new[] { ImmutableStack.Create() }; } T[] wordVariants; var newStack = phrase.Pop(out wordVariants); return FlattenAny(newStack).SelectMany(remainder => wordVariants.Select(word => remainder.Push(word))); } // Fast hard-coded implementation for 3 words private static IEnumerable Flatten3(T[][] phrase) { foreach (var item0 in phrase[0]) { foreach (var item1 in phrase[1]) { foreach (var item2 in phrase[2]) { yield return new T[] { item0, item1, item2, }; } } } } // Fast hard-coded implementation for 4 words private static IEnumerable Flatten4(T[][] phrase) { foreach (var item0 in phrase[0]) { foreach (var item1 in phrase[1]) { foreach (var item2 in phrase[2]) { foreach (var item3 in phrase[3]) { yield return new T[] { item0, item1, item2, item3, }; } } } } } // Fast hard-coded implementation for 5 words private static IEnumerable Flatten5(T[][] phrase) { foreach (var item0 in phrase[0]) { foreach (var item1 in phrase[1]) { foreach (var item2 in phrase[2]) { foreach (var item3 in phrase[3]) { foreach (var item4 in phrase[4]) { yield return new T[] { item0, item1, item2, item3, item4, }; } } } } } } // Fast hard-coded implementation for 6 words private static IEnumerable Flatten6(T[][] phrase) { foreach (var item0 in phrase[0]) { foreach (var item1 in phrase[1]) { foreach (var item2 in phrase[2]) { foreach (var item3 in phrase[3]) { foreach (var item4 in phrase[4]) { foreach (var item5 in phrase[5]) { yield return new T[] { item0, item1, item2, item3, item4, item5, }; } } } } } } } // Fast hard-coded implementation for 7 words private static IEnumerable Flatten7(T[][] phrase) { foreach (var item0 in phrase[0]) { foreach (var item1 in phrase[1]) { foreach (var item2 in phrase[2]) { foreach (var item3 in phrase[3]) { foreach (var item4 in phrase[4]) { foreach (var item5 in phrase[5]) { foreach (var item6 in phrase[6]) { yield return new T[] { item0, item1, item2, item3, item4, item5, item6, }; } } } } } } } } public static IEnumerable Flatten(T[][] wordVariants) { switch (wordVariants.Length) { case 3: return Flatten3(wordVariants); case 4: return Flatten4(wordVariants); case 5: return Flatten5(wordVariants); case 6: return Flatten6(wordVariants); case 7: return Flatten7(wordVariants); default: return FlattenAny(ImmutableStack.Create(wordVariants)).Select(words => words.ToArray()); } } } }