Add `Permutations` method to `EnumerableExtensions` with corresponding tests
This commit is contained in:
parent
56521d39d7
commit
acef1dd7d2
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<TValue[]> Permutations<TValue>(this IEnumerable<TValue> 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<TValue[]> 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<TValue>(int[] innerIndices, TValue[] innerPool) =>
|
||||
innerIndices.Select(i => innerPool[i]).ToArray();
|
||||
}
|
||||
Loading…
Reference in New Issue