using System; using System.Collections.Generic; using System.Diagnostics; // Copyright (c) 2010 Alex Regueiro // Licensed under MIT license, available at . // Published originally at . // Version 1.0, released 22nd May 2010. public static class CombinatoricsUtilities { // Error messages private const string errorMessageValueLessThanZero = "Value must be greater than zero, if specified."; private const string errorMessagesIndicesListInvalidSize = "List of indices must have same size as list of elements."; /// /// Gets all permutations (of a given size) of a given list, either with or without reptitions. /// /// The type of the elements in the list. /// The list of which to get permutations. /// The action to perform on each permutation of the list. /// The number of elements in each resulting permutation; or to get /// premutations of the same size as . /// to get permutations with reptition of elements; /// to get permutations without reptition of elements. /// is . -or- /// is . /// is less than zero. /// /// The algorithm performs permutations in-place. is however not changed. /// public static void GetPermutations(this IList list, Action> action, int? resultSize = null, bool withRepetition = false) { if (list == null) throw new ArgumentNullException("list"); if (action == null) throw new ArgumentNullException("action"); if (resultSize.HasValue && resultSize.Value <= 0) throw new ArgumentException(errorMessageValueLessThanZero, "resultSize"); var result = new T[resultSize.HasValue ? resultSize.Value : list.Count]; var indices = new int[result.Length]; for (int i = 0; i < indices.Length; i++) indices[i] = withRepetition ? -1 : i - 1; int curIndex = 0; while (curIndex != -1) { indices[curIndex]++; if (indices[curIndex] == list.Count) { indices[curIndex] = withRepetition ? -1 : curIndex - 1; curIndex--; } else { result[curIndex] = list[indices[curIndex]]; if (curIndex < indices.Length - 1) curIndex++; else action(result); } } } /// /// Gets all combinations (of a given size) of a given list, either with or without reptitions. /// /// The type of the elements in the list. /// The list of which to get combinations. /// The action to perform on each combination of the list. /// The number of elements in each resulting combination; or to get /// premutations of the same size as . /// to get combinations with reptition of elements; /// to get combinations without reptition of elements. /// is . -or- /// is . /// is less than zero. /// /// The algorithm performs combinations in-place. is however not changed. /// public static void GetCombinations(this IList list, Action> action, int? resultSize = null, bool withRepetition = false) { if (list == null) throw new ArgumentNullException("list"); if (action == null) throw new ArgumentNullException("action"); if (resultSize.HasValue && resultSize.Value <= 0) throw new ArgumentException(errorMessageValueLessThanZero, "resultSize"); var result = new T[resultSize.HasValue ? resultSize.Value : list.Count]; var indices = new int[result.Length]; for (int i = 0; i < indices.Length; i++) indices[i] = withRepetition ? -1 : indices.Length - i - 2; int curIndex = 0; while (curIndex != -1) { indices[curIndex]++; if (indices[curIndex] == (curIndex == 0 ? list.Count : indices[curIndex - 1] + (withRepetition ? 1 : 0))) { indices[curIndex] = withRepetition ? -1 : indices.Length - curIndex - 2; curIndex--; } else { result[curIndex] = list[indices[curIndex]]; if (curIndex < indices.Length - 1) curIndex++; else action(result); } } } /// /// Gets a specific permutation of a given list. /// /// The type of the elements in the list. /// The list to permute. /// The indices of the elements in the original list at each index in the permuted list. /// /// The specified permutation of the given list. /// is . -or- /// is . /// does not have the same size as /// . public static IList Permute(this IList list, IList indices) { if (list == null) throw new ArgumentNullException("list"); if (indices == null) throw new ArgumentNullException("indices"); if (list.Count != indices.Count) throw new ArgumentException(errorMessagesIndicesListInvalidSize, "indices"); var result = new T[list.Count]; for (int i = 0; i < result.Length; i++) result[i] = list[indices[i]]; return result; } }