I want to build a list containing every possible permutation of capitalization of a word. so it would be
List<string> permutate(string word)
{
List<string> ret = new List<string>();
MAGIC HAPPENS HERE
return ret;
}
So say I put in "happy"
I should get an array back of
{happy, Happy, hAppy, HAppy, haPpy, HaPpy ... haPPY, HaPPY, hAPPY, HAPPY}
I know of plenty of functions that will capitalize the first letter but how do I do any arbitrary letter in the word?
You can modify individual characters if you convert your string to an array of char. Something like this should do the trick...
public static List<string> Permute( string s )
{
List<string> listPermutations = new List<string>();
char[] array = s.ToLower().ToCharArray();
int iterations = (1 << array.Length) - 1;
for( int i = 0; i <= iterations; i++ )
{
for( int j = 0; j < array.Length; j++ )
array[j] = (i & (1<<j)) != 0
? char.ToUpper( array[j] )
: char.ToLower( array[j] );
listPermutations.Add( new string( array ) );
}
return listPermutations;
}
Keep in mind that while the accepted answer is the most straightforward way of capitalizing an arbitrary letter, if you are going to change the capitalization repeatedly on the same set of letters (e.g., 32 times in "happy" and growing exponentially for longer words), it will be more efficient to turn the string into a char[], set the appropriate letter(s), and construct the string from the array.
To "permute" your string (technically, this isn't permutation since you're not changing the order of anything, but I don't want to be seen as an an*l-retentive :-), I would use a recursive approach, which basically "permutes" the string minus the first character and attaches those to the upper and lower variations of that character.
Something like (in C, my C# is not really up to par so you'll have to convert it):
#include <stdio.h>
#include <string.h>
static void permute (char *prefix, char *str) {
char *newPrefix;
/* End of string, print and return. */
if (*str == '\0') {
printf ("%s\n", prefix);
return;
}
/* Allocate space for new prefix. */
if ((newPrefix = malloc (strlen (prefix) + 2)) == NULL) {
printf ("ERROR: Cannot allocate memory.\n");
return;
}
/* Do lowercase/sole version and upper version if needed. */
sprintf (newPrefix, "%s%c", prefix, *str);
permute (newPrefix, &(str[1]));
if (islower (*str) {
sprintf (newPrefix, "%s%c", prefix, toupper(*str));
permute (newPrefix, &(str[1]));
}
/* Free prefix and return. */
free (newPrefix);
}
int main (int argc, char *argv[]) {
char *str, *strPtr;
/* Check and get arguments. */
if (argc < 2) {
printf ("Usage: permute <string to permute>\n");
return 1;
}
if ((str = malloc (strlen (argv[1]) + 1)) == NULL) {
printf ("ERROR: Cannot allocate memory.\n");
return 1;
}
strcpy (str, argv[1]);
/* Convert to lowercase. */
for (strPtr = s; *strPtr != '\0'; strPtr++)
*strPtr = toupper (*strPtr);
/* Start recursion with empty prefix. */
permute ("", str);
/* Free and exit. */
free (str);
return 0;
}
Running this as "permute Pax1"
returns:
pax1
paX1
pAx1
pAX1
Pax1
PaX1
PAx1
PAX1
I was able to create a console app that does this..
public static class Program
{
static void Main()
{
Console.WriteLine("Enter string");
string value = Console.ReadLine();
value = value.ToLower();
List<string> list = new List<string>();
var results =
from e in Enumerable.Range(0, 1 << value.Length)
let p =
from b in Enumerable.Range(0, value.Length)
select (e & (1 << b)) == 0 ? (char?)null : value[b]
select string.Join(string.Empty, p);
foreach (string s in results)
{
string newValue = value;
s.ToLower();
foreach(char c in s)
{
var Old = c.ToString().ToLower();
var New = c.ToString().ToUpper();
newValue=ReplaceFirstOccurrence(newValue, Old, New);
}
list.Add(newValue);
}
foreach(string s in list)
{
Console.WriteLine(s);
}
Console.ReadKey();
}
public static string ReplaceFirstOccurrence(string Source, string Find, string Replace)
{
int Place = Source.IndexOf(Find);
string result = Source.Remove(Place, Find.Length).Insert(Place, Replace);
return result;
}
}
I got a list of all possible subsets of characters in the string then for each character in each subset, replaced them with their capital counterparts in the initial string, then made a list of those. Had to have a custom Replace function as the normal string.Replace would replace any occurrence of the character.
It's probably not the cleanest of code, but it does the job. This got brought up as a means of dynamically searching over encrypted fields, and I wanted to see how crazy that would really be..
Loosely speaking, something like below. I may have my ranges off by one, but the idea is sound.
def cap_n(in_str, pos):
leading = in_str.substr(0, pos-1)
trailing = in_str.substr(pos+1) # no second arg implies to end of string
chr = in_str[pos].to_uppercase()
return leading + chr + trailing
Use bitwise operations. For a word of length N you need an integer type represented by N bits. If the word is longer - split it. Iterate through values from 0 to 2N-1 and examine each bit from 0 to N-1. If the bit is 1 - upcase ( Char.ToUpper()
) the letter corresponding to that bit.
This approach is better that a recursive algorithm since it is not prone to stack overflows on long words.
Assuming:
1) You don't care too much that this is O(n*2^n)... although I'm curious to know: what is the best asymptotic run time for this type of problem?
2) Your input is all lowercase.
3) Your input is < 32 characters long. (# of usable bits in the permutation counter, i)
List<string> permutate(string word)
{
List<string> ret = new List<string>();
// MAGIC HAPPENS HERE
Dictionary<char,char> toUppers = new Dictionary<char,char>(26);
toUppers.Add('a', 'A');
toUppers.Add('b', 'B');
toUppers.Add('c', 'C');
toUppers.Add('d', 'D');
toUppers.Add('e', 'E');
toUppers.Add('f', 'F');
toUppers.Add('g', 'G');
toUppers.Add('h', 'H');
toUppers.Add('i', 'I');
toUppers.Add('j', 'J');
toUppers.Add('k', 'K');
toUppers.Add('l', 'L');
toUppers.Add('m', 'M');
toUppers.Add('n', 'N');
toUppers.Add('o', 'O');
toUppers.Add('p', 'P');
toUppers.Add('q', 'Q');
toUppers.Add('r', 'R');
toUppers.Add('s', 'S');
toUppers.Add('t', 'T');
toUppers.Add('u', 'U');
toUppers.Add('v', 'V');
toUppers.Add('w', 'W');
toUppers.Add('x', 'X');
toUppers.Add('y', 'Y');
toUppers.Add('z', 'Z');
char[] wordChars = word.ToCharArray();
int len = wordChars.Length;
// iterate the number of permutations
for(int i = 0; i < 2^len; i++) {
char[] newWord = new char[len]();
// apply "i" as a bitmask to each original char
for(int n = 0; n < newWord.Length; n++) {
if((1 << n) & i != 0) {
newWord[n] = toUppers[wordChars[n]]; // or skip the dictionary and just call Char.ToUpper(wordChars[n])
} else {
newWord[n] = wordChars[n];
}
}
ret.Add(new String(newWord));
}
return ret;
}
Note: I haven't compiled or tested this code. This is also implementing the bitwise compare that sharptooth suggested above.
If order doesn't matter, you can try Linq. We enumerate all binary numbers in a range of [0..2**word.Length]
. and treat each number as mask: 0
- lower case, 1
- upper case. FDor instance for happy
we have
mask string
----------------
00000 -> happy
00001 Happy
00010 hAppy
00011 HAppy
00100 haPpy
00101 HaPpy
...
11111 HAPPY
Code:
using System.Linq;
...
List<string> permutate(string word) =>
Enumerable
.Range(0, 1 << word.Length)
.Select(mask => string.Concat(word.Select((c, i) => (mask & (1 << i)) == 0
? char.ToLower(c)
: char.ToUpper(c))))
.ToList();
Demo:
Console.Write(string.Join(", ", permutate("happy")));
Outcome:
happy, Happy, hAppy, HAppy, haPpy, HaPpy, hAPpy, HAPpy, hapPy, HapPy, hApPy, HApPy, haPPy, HaPPy, hAPPy, HAPPy, happY, HappY, hAppY, HAppY, haPpY, HaPpY, hAPpY, HAPpY, hapPY, HapPY, hApPY, HApPY, haPPY, HaPPY, hAPPY, HAPPY
来源:https://stackoverflow.com/questions/905317/permutations-of-capitalization