计算第N个排列步骤?

我有一个字母az的字符[26]和通过嵌套的语句我正在生成一个序列列表,如:

aaa, aaz... aba, abb, abz, ... zzy, zzz. 

目前,编写软件是为了从aaa-zzz生成所有可能值的列表,然后维护索引,并通过每个值对它们执行操作。

这个列表显然很大,并不是非常大,但它已经达到了内存占用过大的程度(还有其他领域正在研究,但这是我所拥有的)。

我正在尝试生成一个可以保留索引的公式,但是不要使用序列列表并根据当前索引计算当前序列(因为序列之间的操作之间的时间很长)。

例如:

 char[] characters = {a, b, c... z}; int currentIndex = 29; // abd public string CurrentSequence(int currentIndex) { int ndx1 = getIndex1(currentIndex); // = 0 int ndx2 = getIndex2(currentIndex); // = 1 int ndx3 = getIndex3(currentIndex); // = 3 return string.Format( "{0}{1}{2}", characters[ndx1], characters[ndx2], characters[ndx3]); // abd } 

我尝试使用子集(abc)编写一个小例子并尝试使用模数除法进行索引,但是我今天无法思考而且我很难过。

我不是要求答案,只是提供任何帮助。 也许正朝着正确的方向发展?

提示:想想如何在基数26而不是基数10中打印数字,并使用字母而不是数字。 在任意基数中显示数字的一般算法是什么?

剧透 :(向右滚动查看)

  int ndx1 = currentIndex / 26 / 26 % 26; int ndx2 = currentIndex / 26 % 26; int ndx3 = currentIndex % 26; 

这样的事情应该有效,假设有26个字符:

 public string CurrentSequence(int currentIndex) { return characters[currentIndex / (26 * 26)] + characters[(currentIndex / 26) % 26] + characters[currentIndex % 26]; } 

哇, 有一天可以通过笛卡尔积解决两个问题 。 惊人。

您可以使用Eric Lippert的LINQ代码段生成索引值的所有组合。 这种方法产生一组流值,因此它们不需要存储在内存中。 这种方法很好地将生成代码的逻辑与维护状态或执行计算的代码分开。

Eric的所有组合代码:

 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})); } 

你现在可以写:

 public static IEnumerable AllCodes() { char[] characters = {a, b, c... z}; IEnumerable codeSets = new[] { characters, characters, characters }; foreach( var codeValues in codeSets.CartesianProduct() ) { yield return string.Format( "{0}{1}{2}", codeValues[0], codeValues[1], codeValues[2]); } } 

上面的代码生成了从aaazzz的所有代码字符串的流序列。 您现在可以在执行处理的其他地方使用它:

 foreach( var code in AllCodes() ) { // use the code value somehow... } 

有多种方法可以解决您的问题,但一个选项是动态生成序列而不是将其存储在列表中:

 IEnumerable Sequence() { for (var c1 = 'a'; c1 <= 'z'; ++c1) for (var c2 = 'a'; c2 <= 'z'; ++c2) for (var c3 = 'a'; c3 <= 'z'; ++c3) yield return String.Format("{0}{1}{2}", c1, c2, c3); } 

然后,您可以枚举所有字符串:

 foreach (var s in Sequence()) Console.WriteLine(s); 

此代码根本不使用索引,但它允许您使用简单代码创建围绕字符串序列的循环,而不存储字符串。