从字符串中生成特定长度的所有变体
Generating all variations of certain length out of string
我在 C# 中看到了一些字符串变体的实现,但其中 none 对它们的长度有任何限制。不幸的是,我无法修改它们来实现我的目标,例如
用于:
string = "ABCD" and variationLength = 2
生成新字符串:
AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC
我正在寻找这个 Python 的 itertools.permutations 实现,但在 C# 中。 (https://docs.python.org/3/library/itertools.html#itertools.permutations)
在C#中有类似的东西吗?如果没有,那么最简单的实现方式是什么?
Edit_2:
到目前为止,我想出了一个想法来列出给定字符串的所有唯一字符,然后从中获取变体
static void PrintAllKLengthPerm(string str, int k)
{
int n = str.Length;
PrintAllKLengthPermRec(str, "", n, k);
}
// The main recursive method to print all possible strings of length k
static void PrintAllKLengthPermRec(string str, String prefix, int n, int k)
{
// Base case: k is 0, print prefix
if (k == 0)
{
Console.WriteLine(prefix);
return;
}
// One by one add all characters from str and recursively
// call for k equals to k-1
for (int i = 0; i < n; ++i)
{
// Next character of input added
String newPrefix = prefix + str[i];
// k is decreased, because we have added a new character
PrintAllKLengthPermRec(str, newPrefix, n, k - 1);
}
}
static void Main(string[] args)
{
string str = "ABCD";
int permLen = 2;
//get all unique characters in string
string uniqStr = new String(str.Distinct().ToArray());
// Print all possible strings of length permLen out of uniqStr characters
PrintAllKLengthPerm(uniqStr, permLen);
}
但是我正在寻找更优化和有效的解决方案
List<string> newPermutations = new List<string>();
for(int a = 0; a!=inString.Count; a++)
for((int b = 0; b!=inString.Count; b++)
if(noRepetitions && a == b) continue;
newPermutations.Add(""+inString[a] + inString[b]);
我认为这应该可行;我仍在尝试找出一种不仅有 2 个字母的方法。
编辑:编辑后可以用了,旧的就不行了...大声笑
编辑:感谢@Bloopy,他们帮助我发现了 for 循环中的一些错误
我做了以下递归函数来完成你的任务:
static void Permutations(List<string> output, string str, int n, string curr)
{
if(curr.Length == n)
{
output.Add(curr);
return;
}
foreach(char c in str)
if(!curr.Contains(c.ToString()))
Permutations(output, str, n, curr + c.ToString());
}
然后你这样称呼它:
string str = "ABCD";
int length = 2;
List<string> perms = new List<string>();
Permutations(perms, str, length, "");
// now the list "perms" will contain the permutations of "str" in length "n"
这是一个真正的递归排列方法:
public IEnumerable<string> Permutate(string source, int count)
{
if (source.Length == 1)
{
yield return source;
}
else if (count == 1)
{
for (var n = 0; n < source.Length; n++)
{
yield return source.Substring(n, 1);
}
}
else
{
for (var n = 0; n < source.Length; n++)
foreach (var suffix in Permutate(
source.Substring(0, n)
+ source.Substring(n + 1, source.Length - n - 1), count -1))
{
yield return source.Substring(n, 1) + suffix;
}
}
}
可以用Permutate("ABCD", 2)
和returns这样调用:
这是一个使用模和除法的解决方案。使用字母 ABCD 有 4² 个长度为 2 的可能字符串。从 0 到 4²-1 对它们进行编号,并重复将每个数字除以 4。使用所得余数作为 ABCD 字符串的数组索引。
这样做的好处是允许您在需要时保留具有重复元素(AA、BB、CC、DD)的字符串——只需跳过丢弃步骤。
string alphabet = "ABCD";
int length = 2;
int[] indexes = new int[length];
char[] item = new char[length];
// loop through all possible strings for the given alphabet and length
for (int i = 0; i < Math.Pow(alphabet.Length, length); i++) {
int dividend = i;
for (int j = length - 1; j >= 0; j--) {
indexes[j] = dividend % alphabet.Length;
dividend /= alphabet.Length;
}
// discard any that use the same alphabet element more than once
if (indexes.Distinct().Count() < length)
continue;
for (int k = 0; k < length; k++) {
item[k] = alphabet[indexes[k]];
}
Console.WriteLine(item);
}
或者,这是一个使用 LINQ 的非常简短的解决方案。请注意,如果字符串中有重复的元素,此方法将无法正常工作(除非您想删除对 Where
的调用并保留 AA、BB 等)。我需要像在上面的方法中那样跟踪索引。
IEnumerable<string> prm = alphabet.Select(c => c.ToString());
for (int a = 1; a < length; a++)
prm = prm.SelectMany(s => alphabet.Where(t => !s.Contains(t)), (x, y) => x + y);
foreach (string s in prm)
Console.WriteLine(s);
我在 C# 中看到了一些字符串变体的实现,但其中 none 对它们的长度有任何限制。不幸的是,我无法修改它们来实现我的目标,例如
用于:
string = "ABCD" and variationLength = 2
生成新字符串:
AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC
我正在寻找这个 Python 的 itertools.permutations 实现,但在 C# 中。 (https://docs.python.org/3/library/itertools.html#itertools.permutations)
在C#中有类似的东西吗?如果没有,那么最简单的实现方式是什么?
Edit_2: 到目前为止,我想出了一个想法来列出给定字符串的所有唯一字符,然后从中获取变体
static void PrintAllKLengthPerm(string str, int k)
{
int n = str.Length;
PrintAllKLengthPermRec(str, "", n, k);
}
// The main recursive method to print all possible strings of length k
static void PrintAllKLengthPermRec(string str, String prefix, int n, int k)
{
// Base case: k is 0, print prefix
if (k == 0)
{
Console.WriteLine(prefix);
return;
}
// One by one add all characters from str and recursively
// call for k equals to k-1
for (int i = 0; i < n; ++i)
{
// Next character of input added
String newPrefix = prefix + str[i];
// k is decreased, because we have added a new character
PrintAllKLengthPermRec(str, newPrefix, n, k - 1);
}
}
static void Main(string[] args)
{
string str = "ABCD";
int permLen = 2;
//get all unique characters in string
string uniqStr = new String(str.Distinct().ToArray());
// Print all possible strings of length permLen out of uniqStr characters
PrintAllKLengthPerm(uniqStr, permLen);
}
但是我正在寻找更优化和有效的解决方案
List<string> newPermutations = new List<string>();
for(int a = 0; a!=inString.Count; a++)
for((int b = 0; b!=inString.Count; b++)
if(noRepetitions && a == b) continue;
newPermutations.Add(""+inString[a] + inString[b]);
我认为这应该可行;我仍在尝试找出一种不仅有 2 个字母的方法。
编辑:编辑后可以用了,旧的就不行了...大声笑 编辑:感谢@Bloopy,他们帮助我发现了 for 循环中的一些错误
我做了以下递归函数来完成你的任务:
static void Permutations(List<string> output, string str, int n, string curr)
{
if(curr.Length == n)
{
output.Add(curr);
return;
}
foreach(char c in str)
if(!curr.Contains(c.ToString()))
Permutations(output, str, n, curr + c.ToString());
}
然后你这样称呼它:
string str = "ABCD";
int length = 2;
List<string> perms = new List<string>();
Permutations(perms, str, length, "");
// now the list "perms" will contain the permutations of "str" in length "n"
这是一个真正的递归排列方法:
public IEnumerable<string> Permutate(string source, int count)
{
if (source.Length == 1)
{
yield return source;
}
else if (count == 1)
{
for (var n = 0; n < source.Length; n++)
{
yield return source.Substring(n, 1);
}
}
else
{
for (var n = 0; n < source.Length; n++)
foreach (var suffix in Permutate(
source.Substring(0, n)
+ source.Substring(n + 1, source.Length - n - 1), count -1))
{
yield return source.Substring(n, 1) + suffix;
}
}
}
可以用Permutate("ABCD", 2)
和returns这样调用:
这是一个使用模和除法的解决方案。使用字母 ABCD 有 4² 个长度为 2 的可能字符串。从 0 到 4²-1 对它们进行编号,并重复将每个数字除以 4。使用所得余数作为 ABCD 字符串的数组索引。
这样做的好处是允许您在需要时保留具有重复元素(AA、BB、CC、DD)的字符串——只需跳过丢弃步骤。
string alphabet = "ABCD";
int length = 2;
int[] indexes = new int[length];
char[] item = new char[length];
// loop through all possible strings for the given alphabet and length
for (int i = 0; i < Math.Pow(alphabet.Length, length); i++) {
int dividend = i;
for (int j = length - 1; j >= 0; j--) {
indexes[j] = dividend % alphabet.Length;
dividend /= alphabet.Length;
}
// discard any that use the same alphabet element more than once
if (indexes.Distinct().Count() < length)
continue;
for (int k = 0; k < length; k++) {
item[k] = alphabet[indexes[k]];
}
Console.WriteLine(item);
}
或者,这是一个使用 LINQ 的非常简短的解决方案。请注意,如果字符串中有重复的元素,此方法将无法正常工作(除非您想删除对 Where
的调用并保留 AA、BB 等)。我需要像在上面的方法中那样跟踪索引。
IEnumerable<string> prm = alphabet.Select(c => c.ToString());
for (int a = 1; a < length; a++)
prm = prm.SelectMany(s => alphabet.Where(t => !s.Contains(t)), (x, y) => x + y);
foreach (string s in prm)
Console.WriteLine(s);