如何获得一组可复制元素的所有唯一n长组合?

我发现了许多解决方案,它们在所有可能的顺序中组合了一个集合元素,但它们在每个结果中只使用一次元素,而我需要将它们视为可重用的。

例如,如果输入元素为{“a”,“b”,“c”}且数字为2,则输出为{“a”,“a”},{“a”,“b”},{ “a”,“c”},{“b”,“a”},{“b”,“b”},{“b”,“c”},{“c”,“a”},{ “c”,“b”},{“a”,“c”}。

假设你有N个输入元素,你想要一个K-long组合。

您需要做的就是将基数N(当然是一个范围)计入所有具有K位数的数字。

所以,让我们说N = {n0,n1,… nN}

你从数字[n0 n0 … n0]开始,一直计数到[nN nN … nN]

如果你想了解如何计算另一个基数,你可以在这里得到它

您计算的每个数字都映射到您需要的K长组合之一。

我想一个例子会有所帮助

我会用你的价值观。 N = {a,b,c}因此我们想要计入基数3.由于我们需要2长组合,我们只关心2位数字。 最小的2位数基数3是00,所以我们从那里开始。 通过计算基数3,我们得到:

00 01 02 10 11 12 20 21 22 

好的,现在把这些数字转换成一个组合。

请记住,我们的设置是{a,b,c}

因此,每当我们看到0时,它就意味着1.无论我们在哪里看到1,它都意味着2,我相信你能猜出2意味着什么:)

 00 aa 01 ab 02 ac 10 0 => a ba 11 1 => b bb 12 2 => c bc 20 ca 21 cb 22 cc 

您可以使用深度优先搜索 :

 class Program { private static string[] letters = {"a", "b", "c"}; private static void dfs(string accum, int depth) { if (depth == 0) { System.Console.WriteLine(accum); return; } foreach (string c in letters) dfs(accum + c, depth - 1); } public static void Main() { int depth = 2; //Number of letters in each result dfs("", depth); System.Console.ReadLine(); } } 

输出:

 aa ab ac ba bb bc ca cb cc 

埃里克·利珀特(Eric Lippert)提出了一种通用的方法,可以从他在这里发布的任意数量的序列中生成笛卡尔积。

他写了一个扩展方法,如下所示:

 public static class Combinations { public static IEnumerable> CartesianProduct(this IEnumerable> sequences) { IEnumerable> emptyProduct = new[] { Enumerable.Empty() }; return sequences.Aggregate( emptyProduct, (accumulator, sequence) => from accseq in accumulator from item in sequence select accseq.Concat(new[] { item })); } } 

鉴于扩展方法,原始问题的解决方案可以这样做:

 var items = new[] { "a", "b", "c" }; int numInEachSelection = 2; var combs = Enumerable.Repeat(items, numInEachSelection).CartesianProduct(); foreach (var comb in combs) Console.WriteLine(string.Join(", ", comb)); 

请注意, combs是一个IEnumerable> – 它是一个枚举序列,每个枚举数是一个代表一个组合的序列。

如果您不需要这样的通用方法,并且您很乐意将每个组合放在一个单独的对象中,该对象具有两个组合项的名为Item1Item2属性,最简单的方法是:

 var items = new[] { "a", "b", "c" }; var combs = from Item1 in items from Item2 in items select new {Item1, Item2}; foreach (var comb in combs) Console.WriteLine(comb); 

简单 – 你算一算。 如果您有3个元素,如您的示例所示,并且想要所有双元素组合,则只需从0到8(3 ^ 2 – 1)计数,并将结果视为基数为3的数字,并将元素作为数字。

如果您有15个元素并且想要8个元素组合,则从0到15 ^ 8-1计数并将结果视为基数为15的数字。

你要求的是排列而不是组合。 通过n个元素的k遍树遍历可以找到唯一的组合。 如果你想要n个n个元素,那么答案是1