Reputation: 57
I've seen few implementations of variations of string in C#, but none of them had any limitation on their length. Unfortunately, I cannot modify them to achieve my goal which is e.g.
for:
string = "ABCD" and variationLength = 2
generate new strings:
AB, AC, AD, BA, BC, BD, CA, CB, CD, DA, DB, DC
I'm looking for exactly this Python's itertools.permutations implementation but in C#. (https://docs.python.org/3/library/itertools.html#itertools.permutations)
Is there anything similar to its in C#? If not, then what is the easiest way to implement it?
Edit_2: so far I came up with an idea to list all unique chars of given string and then get variations out of them
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);
}
However I am looking for more optimal and effective solution
Upvotes: 0
Views: 2361
Reputation: 4288
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]);
I think that that should work; I am still trying to figure out a way to not only have 2 letters.
Edit: Edited it to work, the old one just didn't work... lol Edit: Thanks to @Bloopy, they helped me spot some errors in my for loops
Upvotes: 1
Reputation: 429
Here's a solution using modulo and division. There are 4² possible strings of length 2 using the letters ABCD. Number them from 0 to 4²-1 and repeatedly divide each number by 4. Use the resulting remainders as array indexes on the ABCD string.
This has the advantage of allowing you to keep the strings with repeated elements (AA, BB, CC, DD) when needed – just skip the discard step.
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);
}
Alternatively, here's a really brief solution using LINQ. Note that this one doesn't work correctly if there are duplicate elements in the string (unless you want to remove the call to Where
and keep the AA, BB etc.). I'd need to track the indexes like I did in my method above.
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);
Upvotes: 0
Reputation: 117064
Here's a truly recursive permutation method:
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;
}
}
}
It can be called with Permutate("ABCD", 2)
and returns this:
Upvotes: 1
Reputation: 537
I made the following recursive function which accomplishes your task:
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());
}
and then you call it like this:
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"
Upvotes: 1