Last active
September 28, 2017 06:16
-
-
Save rvhuang/b203f12a8aed98858ac8bffa8db1093a to your computer and use it in GitHub Desktop.
A set of extension methods enumerating all permutations using Heap's algorithm.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace Extensions | |
{ | |
public static class PermutationsExtension | |
{ | |
public static IEnumerable<string> GetPermutations(this string str) | |
{ | |
return GetPermutations<string, char>(str, array => new string(array)); | |
} | |
public static IEnumerable<TCollection> GetPermutations<TCollection, TElement>(this TCollection elements, | |
Func<TElement[], TCollection> factory) | |
where TCollection : IEnumerable<TElement> | |
{ | |
var array = elements.ToArray(); | |
var indices = new int[array.Length]; // TODO: Replace this with System.Buffers.ArrayPool<T> in future. | |
var i = 0; | |
yield return elements; // Initial permutation | |
while (i < array.Length) | |
{ | |
if (indices[i] < i) | |
{ | |
if (i % 2 == 0) | |
array.Swap(0, i); | |
else | |
array.Swap(indices[i], i); | |
yield return factory(array); | |
indices[i]++; | |
i = 0; | |
} | |
else | |
{ | |
indices[i] = 0; | |
i++; | |
} | |
} | |
} | |
public static IEnumerable<string> GetPermutationsWithoutRepetition(this string str) | |
{ | |
return GetPermutationsWithoutRepetition<string, char>(str, array => new string(array), StringComparer.Ordinal); | |
} | |
public static IEnumerable<string> GetPermutationsWithoutRepetition(this string str, StringComparison comparison) | |
{ | |
return GetPermutationsWithoutRepetition(str, StringComparer.FromComparison(comparison)); | |
} | |
public static IEnumerable<string> GetPermutationsWithoutRepetition(this string str, IEqualityComparer<string> comparer) | |
{ | |
return GetPermutationsWithoutRepetition<string, char>(str, array => new string(array), comparer); | |
} | |
public static IEnumerable<TCollection> GetPermutationsWithoutRepetition<TCollection, TElement>(this TCollection elements, | |
Func<TElement[], TCollection> factory, IEqualityComparer<TCollection> comparer) | |
where TCollection : IEnumerable<TElement> | |
{ | |
var current = default(TCollection); | |
var array = elements.ToArray(); | |
var history = new HashSet<TCollection>(comparer); | |
var indices = new int[array.Length]; // TODO: Replace this with System.Buffers.ArrayPool<T> in future. | |
var i = 0; | |
history.Add(elements); | |
yield return elements; // Initial permutation | |
while (i < array.Length) | |
{ | |
if (indices[i] < i) | |
{ | |
var swapped = false; | |
if (i % 2 == 0) | |
swapped = array.SwapIfNotEqual(0, i); | |
else | |
swapped = array.SwapIfNotEqual(indices[i], i); | |
if (swapped && history.Add(current = factory(array))) | |
yield return current; | |
indices[i]++; | |
i = 0; | |
} | |
else | |
{ | |
indices[i] = 0; | |
i++; | |
} | |
} | |
} | |
public static void Swap<T>(this IList<T> elements, int index1, int index2) | |
{ | |
var temp = elements[index1]; | |
elements[index1] = elements[index2]; | |
elements[index2] = temp; | |
} | |
public static bool SwapIfNotEqual<T>(this IList<T> elements, int index1, int index2) | |
{ | |
return SwapIfNotEqual(elements, index1, index2, EqualityComparer<T>.Default); | |
} | |
public static bool SwapIfNotEqual<T>(this IList<T> elements, int index1, int index2, EqualityComparer<T> comparer) | |
{ | |
var temp = elements[index1]; | |
comparer = comparer ?? EqualityComparer<T>.Default; | |
if (comparer.Equals(temp, elements[index2])) return false; | |
elements[index1] = elements[index2]; | |
elements[index2] = temp; | |
return true; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment