I want to build a list containing every possible permutation of capitalization of a word. so it would be
List permutate(string word)
{
List
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.
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
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.
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. For 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