Skip to content

Instantly share code, notes, and snippets.

@rvhuang
Last active September 28, 2017 06:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rvhuang/b203f12a8aed98858ac8bffa8db1093a to your computer and use it in GitHub Desktop.
Save rvhuang/b203f12a8aed98858ac8bffa8db1093a to your computer and use it in GitHub Desktop.
A set of extension methods enumerating all permutations using Heap's algorithm.
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