列表的独特组合

绝对的心灵空白。 那是其中的一天。 但我一直在寻找一种解决方案,以获得一定长度的项目列表的独特组合。 例如,给定一个列表[a,b,c]和长度为2,它将返回[a,b] [a,c] [b,c]但不返回[b,a] [c,a] [c ,b]的

为此,我发现了许多代码,但似乎没有一个代码。 以下代码似乎最合适,我一直在尝试根据我的需要改变它:

// Returns an enumeration of enumerators, one for each permutation // of the input. public static IEnumerable<IEnumerable> Permute(IEnumerable list, int count) { if (count == 0) { yield return new T[0]; } else { int startingElementIndex = 0; foreach (T startingElement in list) { IEnumerable remainingItems = AllExcept(list, startingElementIndex); foreach (IEnumerable permutationOfRemainder in Permute(remainingItems, count - 1)) { yield return Concat( new T[] { startingElement }, permutationOfRemainder); } startingElementIndex += 1; } } } // Enumerates over contents of both lists. public static IEnumerable Concat(IEnumerable a, IEnumerable b) { foreach (T item in a) { yield return item; } foreach (T item in b) { yield return item; } } // Enumerates over all items in the input, skipping over the item // with the specified offset. public static IEnumerable AllExcept(IEnumerable input, int indexToSkip) { int index = 0; foreach (T item in input) { if (index != indexToSkip) yield return item; index += 1; } } 

这可以做它应该做的事情,但它返回所有排列,无论它们是唯一的。 我试图让我的头围绕这个代码的哪一块(如果有的话)改变以获得唯一值。 或者是实现此function的更好方法?

实现中的其余项目列表包含除当前起始项目之外的所有项目。

改为获取起始项目之后的项目:

 IEnumerable remainingItems = list.Skip(startingElementIndex + 1); 

试试这个:

 void Main() { var list = new List { "a", "b", "c", "d", "e" }; var result = GetPermutations(list, 3); } IEnumerable> GetPermutations(IEnumerable items, int count) { int i = 0; foreach(var item in items) { if(count == 1) yield return new T[] { item }; else { foreach(var result in GetPermutations(items.Skip(i + 1), count - 1)) yield return new T[] { item }.Concat(result); } ++i; } } 

对于2的计数,它返回:

 a, b a, c a, d a, e b, c b, d b, e c, d c, e d, e 

对于3的计数,它返回:

 a, b, c a, b, d a, b, e a, c, d a, c, e a, d, e b, c, d b, c, e b, d, ec, d, e 

这是你期望的吗?

而不是AllExcept,您应该使用一个子序列,只给出您正在考虑的项目之后的项目。

在set-speak中,您正在寻找的是基于长度n的功率集的子集。 如果您在谷歌搜索“C#”+“电源设置”,应该可以为您提供足够的入门。

http://en.wikipedia.org/wiki/Power_set

并且只是为了完整性..如果你已经有了所有的排列(:)并且因为它只是我的复制和粘贴),下面的扩展方法你可以得到不同的结果,如下所示:

 var result = permutations.Distinct((p1, p2) => !p1.Differs(p2)); 

只是一个例子,如果您使用比较列表很多,其他方法也可能在其他地方派上用场

 public static class Extensionmethods { ///  /// Checks if both IEnumerables contain the same values regardless of their sequence ///  /// Type of Elements /// IEnumerable to compare to /// IEnumerable to compare to /// Returns false if both IEnumerables contain the same values public static bool Differs(this IEnumerable result, IEnumerable compare) { if (result == null && compare == null) return false; if (result != null && compare == null) return true; if (result == null && compare != null) return true; return result.Count() != compare.Count() || compare.Where(c => c == null).Count() != result.Where(r => r == null).Count() || compare.Where(c => c != null).Distinct().Any(item => result.Where(r => item.Equals(r)).Count() != compare.Where(r => item.Equals(r)).Count()); } ///  /// Checks if both IEnumerables contain the same values (corresponding to  regardless of their sequence ///  /// Type of Elements /// IEnumerable to compare to /// IEnumerable to compare to /// IEqualityComparer to use /// Returns false if both IEnumerables contain the same values public static bool Differs(this IEnumerable result, IEnumerable compare, IEqualityComparer comparer) { if (result == null && compare == null) return false; if (result != null && compare == null) return true; if (result == null && compare != null) return true; return result.Count() != compare.Count() || compare.Where(c => c == null).Count() != result.Where(r => r == null).Count() || compare.Where(c => c != null).Distinct().Any(item => result.Where(r => comparer.Equals(item, r)).Count() != compare.Where(r => comparer.Equals(item, r)).Count()); } public static IEnumerable Distinct(this IEnumerable source, Func compareFunction, Func hashFunction = null) { var ecomparer = new DynamicEqualityComparer(compareFunction, hashFunction); return source.Distinct(ecomparer); } } internal class DynamicEqualityComparer : IEqualityComparer { public DynamicEqualityComparer(Func equalFunction, Func hashFunction = null) { this.equalFunc = equalFunction; this.hashFunc = hashFunction; } private Func equalFunc; public bool Equals(T x, T y) { if (x == null && y == null) return true; if (x == null) return false; if (y == null) return false; if (hashFunc != null) { if (hashFunc.Invoke(x) != hashFunc.Invoke(y)) return false; } return this.equalFunc.Invoke(x, y); } private Func hashFunc; public int GetHashCode(T obj) { if (hashFunc != null) return hashFunc.Invoke(obj); return 0; } }