diff --git a/AdventOfCode.Extensions.Tests/EnumerableExtensionsTest.cs b/AdventOfCode.Extensions.Tests/EnumerableExtensionsTest.cs index 2505f10..3269f63 100644 --- a/AdventOfCode.Extensions.Tests/EnumerableExtensionsTest.cs +++ b/AdventOfCode.Extensions.Tests/EnumerableExtensionsTest.cs @@ -34,4 +34,33 @@ public class EnumerableExtensionsTest Assert.Contains([1, 2, 3], actual); } + + [Fact] + public void Permutations_12_2_equals_11_12_21_22() + { + int[] data = [1, 2]; + + var actual = data.Permutations(2).ToArray(); + + Assert.Contains([1, 1], actual); + Assert.Contains([1, 2], actual); + Assert.Contains([2, 1], actual); + Assert.Contains([2, 2], actual); + } + + [Fact] + public void Permutations_123_2_equals_11_12_13_21_22_23_31_32_33() + { + int[] data = [1, 2, 3]; + + var actual = data.Permutations(2).ToArray(); + + Assert.Contains([1, 1], actual); + Assert.Contains([1, 2], actual); + Assert.Contains([2, 1], actual); + Assert.Contains([2, 2], actual); + Assert.Contains([3, 1], actual); + Assert.Contains([3, 2], actual); + Assert.Contains([3, 3], actual); + } } \ No newline at end of file diff --git a/AdventOfCode.Extensions/EnumerableExtensions.cs b/AdventOfCode.Extensions/EnumerableExtensions.cs index 76244ee..7c54e47 100644 --- a/AdventOfCode.Extensions/EnumerableExtensions.cs +++ b/AdventOfCode.Extensions/EnumerableExtensions.cs @@ -16,8 +16,8 @@ public static class EnumerableExtensions yield return GetCombination(indices, pool); while (true) { - int idx; - for(idx = count - 1; idx >= 0; idx--) + var idx = count - 1; + for(;idx >= 0; --idx) { var isIndexBelowMax = indices[idx] != idx + poolLength - count; if (isIndexBelowMax) @@ -34,8 +34,47 @@ public static class EnumerableExtensions yield return GetCombination(indices, pool); } - - static TValue[] GetCombination(int[] innerIndices, TValue[] innerPool) => - innerIndices.Select(i => innerPool[i]).ToArray(); } + + public static IEnumerable Permutations(this IEnumerable values, int count) + { + var pool = values.ToArray(); + if (count > pool.Length) + yield break; + foreach (var p in InnerPermutations(pool, count)) + yield return p; + + foreach (var p in InnerPermutations([..pool.Reverse()], count)) + yield return p; + yield break; + + static IEnumerable InnerPermutations(TValue[] pool, int count) + { + var indices = Enumerable.Repeat(0, count).ToArray(); + yield return GetCombination(indices, pool); + while (true) + { + var idx = count - 1; + for(;idx >= 0; --idx) + { + var isIndexBelowMax = indices[idx] != idx + pool.Length - count; + if (isIndexBelowMax) + break; + } + if(idx < 0) + break; + + indices[idx] += 1; + for (var j = idx + 1; j < count; j++) + { + indices[j] = indices[j - 1]; + } + + yield return GetCombination(indices, pool); + } + } + } + + private static TValue[] GetCombination(int[] innerIndices, TValue[] innerPool) => + innerIndices.Select(i => innerPool[i]).ToArray(); } \ No newline at end of file