绝对的头脑空白。那是其中的一天。但我一直在寻找一种解决方案,以获得一定长度的项目列表的独特组合。例如,给定一个列表[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<T>> Permute<T>(IEnumerable<T> list, int count)
{
if (count == 0)
{
yield return new T[0];
}
else
{
int startingElementIndex = 0;
foreach (T startingElement in list)
{
IEnumerable<T> remainingItems = AllExcept(list, startingElementIndex);
foreach (IEnumerable<T> permutationOfRemainder in Permute(remainingItems, count - 1))
{
yield return Concat<T>(
new T[] { startingElement },
permutationOfRemainder);
}
startingElementIndex += 1;
}
}
}
// Enumerates over contents of both lists.
public static IEnumerable<T> Concat<T>(IEnumerable<T> a, IEnumerable<T> 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<T> AllExcept<T>(IEnumerable<T> input, int indexToSkip)
{
int index = 0;
foreach (T item in input)
{
if (index != indexToSkip) yield return item;
index += 1;
}
}
这可以做它应该做的事情,但它返回所有排列,无论它们是唯一的。我试图让我的头围绕这个代码的哪一块(如果有的话)改变以获得唯一值。或者是实现此功能的更好方法吗?
答案 0 :(得分:13)
试试这个:
void Main()
{
var list = new List<string> { "a", "b", "c", "d", "e" };
var result = GetPermutations(list, 3);
}
IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> 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, e
c, d, e
这是你期望的吗?
答案 1 :(得分:3)
实施中的其余项目列表包含除当前起始项目之外的所有项目。
获取起始项目之后的项目:
IEnumerable<T> remainingItems = list.Skip(startingElementIndex + 1);
答案 2 :(得分:1)
而不是AllExcept,您应该使用一个子序列,只为您提供正在考虑的项目之后的项目。
答案 3 :(得分:0)
在set-speak中,您正在寻找的是基于长度n的功率集的子集。如果您在谷歌搜索“C#”+“Power set”,那么应该为您提供足够的入门时间。
答案 4 :(得分:0)
只是为了完整..如果你已经有了所有的排列 (:)因为它只是我的复制和粘贴) 使用下面的扩展方法,您可以得到不同的结果:
var result = permutations.Distinct((p1, p2) => !p1.Differs(p2));
只是一个例子,如果您使用比较列表很多,其他方法也可能在其他地方派上用场
public static class Extensionmethods
{
/// <summary>
/// Checks if both IEnumerables contain the same values regardless of their sequence
/// </summary>
/// <typeparam name="T">Type of Elements</typeparam>
/// <param name="result">IEnumerable to compare to</param>
/// <param name="compare">IEnumerable to compare to</param>
/// <returns>Returns false if both IEnumerables contain the same values</returns>
public static bool Differs<T>(this IEnumerable<T> result, IEnumerable<T> 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());
}
/// <summary>
/// Checks if both IEnumerables contain the same values (corresponding to <paramref name="comparer"/> regardless of their sequence
/// </summary>
/// <typeparam name="T">Type of Elements</typeparam>
/// <param name="result">IEnumerable to compare to</param>
/// <param name="compare">IEnumerable to compare to</param>
/// <param name="comparer">IEqualityComparer to use</param>
/// <returns>Returns false if both IEnumerables contain the same values</returns>
public static bool Differs<T>(this IEnumerable<T> result, IEnumerable<T> compare, IEqualityComparer<T> 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<T> Distinct<T>(this IEnumerable<T> source, Func<T, T, bool> compareFunction, Func<T, int> hashFunction = null)
{
var ecomparer = new DynamicEqualityComparer<T>(compareFunction, hashFunction);
return source.Distinct(ecomparer);
}
}
internal class DynamicEqualityComparer<T> : IEqualityComparer<T>
{
public DynamicEqualityComparer(Func<T, T, bool> equalFunction, Func<T, int> hashFunction = null)
{
this.equalFunc = equalFunction;
this.hashFunc = hashFunction;
}
private Func<T, T, bool> 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<T, int> hashFunc;
public int GetHashCode(T obj)
{
if (hashFunc != null) return hashFunc.Invoke(obj);
return 0;
}
}
答案 5 :(得分:0)
我已经尝试了上述所有方法,但均失败了,因为它们吃了很多Ram,如果输入量较大,则会崩溃。但是我有一个非常非常简单的解决方案:
class Program
{
static List<string> textArr = new List<string>() { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
static void Main(string[] args)
{
getCombination();
}
static void getCombination() {
var maxCombination = 1;
List<string> Combinations = new List<string>();
for (var i = 1; i < textArr.Count(); i++)
{
maxCombination = maxCombination * i;
}
while (Combinations.Count<maxCombination)
{
var temp = string.Join(" ", textArr.OrderBy(x => Guid.NewGuid()).ToList());
if (Combinations.Contains(temp))
{
continue;
}
else {
Combinations.Add(temp);
}
}
}
}