Breaking Down & Rearranging String into all possible combinations - c#

I want to break down and rearranging a string into all possible combinations
Say I have a String: ABCDEF
I want to break it down and output all possible combinations
Combination(6,6) = 1
ABCDEF
Combination(6,5) = 6
BCDEF
ACDEF
ABDEF
ABCEF
ABCDF
ABCDE
Combination(6,4) = 15
BCDE
ACDE
ABDE
ABCE
....
....
....
etc.
Combination(6,3) = 20
BCD
ACD
...
etc.
Combination(6,2) = 15
BC
AB
etc.
However the ouptut must also be arranged into alphabetical order.
How will I do this?
Thanks! Any help will be appreciated!

You can get the algorithm (actually a few of them) from Knuth Volume 4, Fascicle 3 but you'll have to convert it from his math notation to C#.
Update: As I think about this more, Fascicle 2 (Generating Permutations) is actually more helpful. You can download it free from http://www-cs-faculty.stanford.edu/~knuth/fasc2b.ps.gz though you'll need gunzip and a PostScript previewer to read it. Generating the subsets of string "ABCDE" is the easy part. Convert it to an array {'A', 'B', 'C', 'D', 'E'}, run a for loop from 0 to 2^N-1 where N is the array length, and treat each value as a bitmask of the elements you're keeping. Thus 00001, 00010, 00011,... gives you "A", "B", "AB",...
The hard part is generating all the permutations of each subset, so you get "ABC", "BAC", "CAB", etc. A brute force algorithm (like in one of the other answers) will work but will get very slow if the string is long. Knuth has some fast algorithms, some of which will generate the permutations in alphabetical order if the original string was sorted in the first place.

Well, to expand on my comment, how I got past this problem was transforming the string into a hash that doesn't care the order of the letters. The hash works by taking each unique letter, then a :, then the number of times that letter occurs.
So test = e:1,s:1,t:2
Then if somebody looks for the world tset, it would generate the same hash (e:1,s:1,t:2), and bam you have a match.
I just ran a word list (of about 20 million words), generated a hash for each one of them, and put it in a mysql table, I can find all permutations of a word (that are still words themselves, aka ered will return deer and reed) in seconds.

You can generate each permutation by incrementing a counter and converting the counter value to base n where n is the number of letters in your input. Discard any values containing repeating letters and what you have left are the possible scrabble words in alphabetic order assuming your array was sorted.
You will have to count up to (n^(n-1))*(n+1) to get the e*n! possible scrabble words.
char[] Letters = new char[] { 'A', 'B', 'C', 'D', 'E', 'F' };
// calculate e*n! (int)Math.Floor(Math.E * Math.Factorial(Letters.Length))
int x = 0;
for (int i = 1; i <= Letters.Length; i++)
x = (x + 1) * i;
for (int i = 1; x > 0; i++)
{
string Word = BaseX(i, Letters.Length, Letters);
if (NoRepeat(Word))
{
Console.WriteLine(Word);
x--;
}
}
BaseX returns the string representation of Value for the given Base and specified Symbols:
string BaseX(int Value, int Base, char[] Symbols)
{
StringBuilder s = new StringBuilder();
while (Value > Base)
{
s.Insert(0, Symbols[Value % Base]);
Value /= Base;
}
s.Insert(0, Symbols[Value - 1]);
return s.ToString();
}
NoRepeat returns false if any letter occurs more than once:
bool NoRepeat(string s)
{
bool[] Test = new bool[256];
foreach (char c in s)
if (Test[(byte)c])
return false;
else
Test[(byte)c] = true;
return true;
}

Sort the string in alphabet order. Say ABCDEF (your example)
Prepare a map between index and character
map[0] = 'A'; map[1] = 'B'; ... map[5] = 'F'
3 . Now your job is a lot more simple: find all combinations of number in which the later number is larger than the former
Combination(6,3):
for (int i = 0; i < 6 - 2; i++)
for (int j = i + 1; j < 6 - 1; j++)
for (int k = j + 1; k < 6; k++)
{
string strComb = map[i] + map[j] + map[k];
}
This is mainly the idea, you could improve in your own way.
Contact me if you want more detail!

You can use this:
static List<string> list = new List<string>();
static string letters = "bcdehijkmnopqrstuvwxyz";
static void Combine(string combinatory)
{
if(combinatory.Length < letters.Length)
{
Parallel.ForEach(letters, l =>
{
if (!combinatory.Contains(l)) Combine(combinatory + l);
});
} else
{
list.Add(combinatory);
Console.WriteLine(combinatory);
}
}
It will add to the list List all the possible combinations.
Then you can use the Sort() method in order to sort the list.

Related

How do I add integers to char[] array?

So I have to write a code that picks our random numbers from 1 to 100 and add them to a char[] array. But I'm having some difficulty doing so as I can only add the numbers to the array if I convert them to a char using (char) which changes the number. Can someone please help me?
Thanks,
public char[] CreationListe(int nmbrevaleurTirés)
{
char[] l = new char[nmbrevaleurTirés];
for (int i = 0; i < nmbrevaleurTirés; i++)
{
l[i] = (char)(new Random().Next(1, 101));
}
return l;
}
use ToChar() method of Convert class.
Convert.ToChar(new Random().Next(1, 101))
You cannot convert an integer larger then 9 into a char because it's considered as 2 chars, i.e. 10 will be considered as 1 and 0.
so I would recommend adding it to an array of strings
(except if your trying to get a random charcode which I dont think is the case, because why till 100?)
Personally, I'd use an int[] array instead
There shouldn't be any problem in storing ints up to 65535 in a char but you will have to cast it back to an int if you don't want it to be weird:
public static void Main()
{
var x = CreationListe(200);
foreach(var c in x)
Console.WriteLine((int)c); //need to cast to int!
}
public static char[] CreationListe(int nmbrevaleurTirés)
{
char[] l = new char[nmbrevaleurTirés];
for (int i = 0; i < nmbrevaleurTirés; i++)
{
l[i] = (char)(new Random().Next(1, 65536));
}
return l;
}
https://dotnetfiddle.net/z5yoBn
If you don't cast it back to int, then you'll get the char at that character index in the unicode table. If you've put 65 into a char, you'll get A when you print it, for example. This is because A is at position 65 in the table:
(ASCII table image posted for brevity's sake)

How would I add to an integer based on characters in a string?

Basically, I'm creating a game and I have gotten to the stage where I need to add a score to an integer.
Lets say that the integer is called totalScore.
I currently have a string named spacedLetters which contains 7 letters randomly picked from a 26 letter array (the alphabet). I have created a simple:
Console.WriteLine("Please Enter A Word:");
userInput = Console.ReadLine();
Section that allows the user to input a word. All I want to do is to check through this string that they input (userInput) and add a value to totalScore based on what letters are in the word they inputted.
This should work a bit like scrabble as if they input room, it would value the r, then the o, then the other o, then the m and add a value that is assigned to these letters to the total score. I understand that I will need a reference table as well but I simply don't know how to do this.
TL;DR, I need a reference table for letters in the alphabet to correspond to a certain number (Like scrabble) and I need some code that checks through each letter in the users input and adds a value to a number based on if their word contains that letter. It also needs to account for duplicate letters, such as in the word room.
Thank you.
EDIT:
I ended up using the code:
for (i = 0; i < 10; i++)
{
if (userInput.Contains(valueOf1[i]))
{
length1 = length1 + 1;
totalScore = totalScore + 1;
}
}
People provided solutions but they were not what I was looking for, especially concerning my code, therefore no answer chosen.
The following skeleton of an algorithm should do the trick (sorry for posting F# code, I tend to think faster in it than in C#; translating it should be quite straightforward, though):
let createRandomScores (n : int) =
let r = System.Random ()
let rec loop acc score =
if score > n then dict acc else
let x = char (r.Next (97, 123)), score
loop (x :: acc) (score + 1)
loop [] 1
let scoreDict = createRandomScores 6
let scoreWord (word : string) =
let matchChar c =
match scoreDict.TryGetValue c with
| true, s -> s | _ -> 0
word |> Seq.map matchChar
|> Seq.sum
let addWordToScore score word =
score + scoreWord word
EDIT: This might look as follows in C#:
static Dictionary<char, int> CreateRandomScores(int n)
{
var r = new Random();
var scores = new Dictionary<char, int>();
for (var score = 1; score <= n; score++)
scores[(char)r.Next(97, 123)] = score;
return scores;
}
Dictionary<char, int> ScoreDict = CreateRandomScores(6);
static int ScoreWord(string word)
{
var wordScore = 0;
foreach (var c in word)
if (ScoreDict.TryGetValue(c, out s))
wordScore += s;
return wordScore;
}
static int AddWordToScore(int score, string word)
{
return score + ScoreWord(word);
}
for (i = 0; i < 10; i++)
{
if (userInput.Contains(valueOf1[i]))
{
length1 = length1 + 1;
totalScore = totalScore + 1;
}
}

Adding 'space' in C# textbox

Hi guys, so I need to add a 'space' between each character in my displayed text box.
I am giving the user a masked word like this He__o for him to guess and I want to convert this to H e _ _ o
I am using the following code to randomly replace characters with '_'
char[] partialWord = word.ToCharArray();
int numberOfCharsToHide = word.Length / 2; //divide word length by 2 to get chars to hide
Random randomNumberGenerator = new Random(); //generate rand number
HashSet<int> maskedIndices = new HashSet<int>(); //This is to make sure that I select unique indices to hide. Hashset helps in achieving this
for (int i = 0; i < numberOfCharsToHide; i++) //counter until it reaches words to hide
{
int rIndex = randomNumberGenerator.Next(0, word.Length); //init rindex
while (!maskedIndices.Add(rIndex))
{
rIndex = randomNumberGenerator.Next(0, word.Length); //This is to make sure that I select unique indices to hide. Hashset helps in achieving this
}
partialWord[rIndex] = '_'; //replace with _
}
return new string(partialWord);
I have tried : partialWord[rIndex] = '_ ';however this brings the error "Too many characters in literal"
I have tried : partialWord[rIndex] = "_ "; however this returns the error " Cannot convert type string to char.
Any idea how I can proceed to achieve a space between each character?
Thanks
The following code should do as you ask. I think the code is pretty self explanatory., but feel free to ask if anything is unclear as to the why or how of the code.
// char[] partialWord is used from question code
char[] result = new char[(partialWord.Length * 2) - 1];
for(int i = 0; i < result.Length; i++)
{
result[i] = i % 2 == 0 ? partialWord[i / 2] : ' ';
}
return new string(result);
Since the resulting string is longer than the original string, you can't use only one char array because its length is constant.
Here's a solution with StringBuilder:
var builder = new StringBuilder(word);
for (int i = 0 ; i < word.Length ; i++) {
builder.Insert(i * 2, " ");
}
return builder.ToString().TrimStart(' '); // TrimStart is called here to remove the leading whitespace. If you want to keep it, delete the call.

Need help finding n amount of Excel Ranges

So I have this situation:
At work I need to make an Excel AddIn which can collect some data from user surveys and show them in a neat little Excel Report. I have the format down however I have trouble figuring out how I find the Excel Ranges needed to showcase the questions that were asked in the survey.
Every question needs to take up three cells each since there are three stats associated with each and that's fine until you reach Z and have to start over with AA, AB, AC, etc. I can't quite wrap my head around it and I feel my current solution is being needlessly complicated. I know that right now there are 13 questions. That's 39 cells I need for the questions total but that could change in the future, or I might have to find smaller reports than all of the 13 questions. I need to make sure my algorithm can take care of both scenarios.
Currently I have this:
const String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int alphabetCounter = 0;
int alphabetIndex = 1;
for (int i = 0; i < dict["questions"].Length; i++)
{
String start = "";
String end = "";
if ((alphabetIndex + 1) > ALPHABET.Length)
{
alphabetCounter++;
alphabetIndex = 0;
start += ALPHABET[alphabetCounter - 1] + ALPHABET[alphabetIndex];
}
else
{
start += ALPHABET[alphabetIndex];
alphabetIndex++;
}
if ((alphabetIndex + 1) > ALPHABET.Length)
{
alphabetCounter++;
alphabetIndex = 0;
end += ALPHABET[alphabetIndex];
}
else
{
alphabetIndex++;
end += ALPHABET[alphabetIndex];
}
Excel.Range range = sheet.get_Range(start + "7", end + "7");
questionRanges.Add(range);
}
It's not finished because I ran into a wall here. So just to explain:
ALPHABET is just that. The alphabet. I use that to get the cell letters.
AlphabetCounter is how many times I have gone through the alphabet so in the event that I need to add an extra letter in front of my cells letter (Like the A in AB) I can get that from the ALPHABET string
AlphabetIndex is where in the alphabet I currently am.
I hope you can help me.
How would I go about getting all the ranges I need to accompany the n amount of questions I can get details about?
The trivial solution would be to change
const string ALPHABET = "ABC..."
to
const string[] ColumnNames = { "A", "B", "C", ..., "Z", "AA".. }
But this doesn't scale well. Think about what happens when you need to add a column. You'd have to add another item in the array, and eventually you'd have 26^2 array entries. Certainly not ideal.
A better solution would be to treat the column index as a base 26 number and convert it using a function like the following:
string GetColumnName(int index)
{
List<char> chars = new List<char>();
while (index >= 0)
{
int current = index % 26;
chars.Add((char)('A' + current));
index = (int)((index - current) / 26) - 1;
}
chars.Reverse();
return new string(chars.ToArray());
}
The function here converts the base by repeatedly calculating the remainder (also known as modulus or %).
just another idea of implementation, maybe it can be useful:
...
List<char> start = new List<char>();
List<char> end = new List<char>();
start = Increment(end);
Increment(end);
Increment(end);
Excel.Range range = sheet.get_Range(new String(start.ToArray())+ "7",
new String(end.ToArray())+ "7");
}
private List<char> Increment(List<char> listColumn, int position=0)
{
if (listColumn.Count > position)
{
listColumn[position]++;
if (listColumn[position] == '[')
{
listColumn[position] = 'A';
Increment(listColumn, ++position);
}
}
else
{
listColumn.Add('A');
}
return listColumn;
}

erroneous character fixing of strings in c#

I have five strings like below,
ABBCCD
ABBDCD
ABBDCD
ABBECD
ABBDCD
all the strings are basically same except for the fourth characters. But only the character that appears maximum time will take the place. For example here D was placed 3 times in the fourth position. So, the final string will be ABBDCD. I wrote following code, but it seemed to be less efficient in terms of time. Because this function can be called million times. What should I do to improve the performance?
Here changedString is the string to be matched with other 5 strings. If Any position of the changed string is not matched with other four, then the maxmum occured character will be placed on changedString.
len is the length of the strings which is same for all strings.
for (int i = 0; i < len;i++ )
{
String findDuplicate = string.Empty + changedString[i] + overlapStr[0][i] + overlapStr[1][i] + overlapStr[2][i] +
overlapStr[3][i] + overlapStr[4][i];
char c = findDuplicate.GroupBy(x => x).OrderByDescending(x => x.Count()).First().Key;
if(c!=changedString[i])
{
if (i > 0)
{
changedString = changedString.Substring(0, i) + c +
changedString.Substring(i + 1, changedString.Length - i - 1);
}
else
{
changedString = c + changedString.Substring(i + 1, changedString.Length - 1);
}
}
//string cleanString = new string(findDuplicate.ToCharArray().Distinct().ToArray());
}
I'm not quite sure what you are going to do, but if it is about sorting strings by some n-th character, then the best way is to use Counting Sort http://en.wikipedia.org/wiki/Counting_sort It is used for sorting array of small integers and is quite fine for chars. It has linear O(n) time. The main idea is that if you know all your possible elements (looks like they can be only A-Z here) then you can create an additional array and count them. For your example it will be {0, 0, 1 ,3 , 1, 0,...} if we use 0 for 'A', 1 for 'B' and so on.
There is a function that might help performance-wise as it runs five times faster. The idea is to count occurrences yourself using a dictionary to convert character to a position into counting array, increment value at this position and check if it is greater than previously highest number of occurrences. If it is, current character is top and is stored as result. This repeats for each string in overlapStr and for each position within the strings. Please read comments inside code to see details.
string HighestOccurrenceByPosition(string[] overlapStr)
{
int len = overlapStr[0].Length;
// Dictionary transforms character to offset into counting array
Dictionary<char, int> char2offset = new Dictionary<char, int>();
// Counting array. Each character has an entry here
int[] counters = new int[overlapStr.Length];
// Highest occurrence characters found so far
char[] topChars = new char[len];
for (int i = 0; i < len; ++i)
{
char2offset.Clear();
// faster! char2offset = new Dictionary<char, int>();
// Highest number of occurrences at the moment
int highestCount = 0;
// Allocation of counters - as previously unseen character arrives
// it is given a slot at this offset
int lastOffset = 0;
// Current offset into "counters"
int offset = 0;
// Small optimization. As your data seems very similar, this helps
// to reduce number of expensive calls to TryGetValue
// You might need to remove this optimization if you don't have
// unused value of char in your dataset
char lastChar = (char)0;
for (int j = 0; j < overlapStr.Length; ++ j)
{
char thisChar = overlapStr[j][i];
// If this is the same character as last one
// Offset already points to correct cell in "counters"
if (lastChar != thisChar)
{
// Get offset
if (!char2offset.TryGetValue(thisChar, out offset))
{
// First time seen - allocate & initialize cell
offset = lastOffset;
counters[offset] = 0;
// Map character to this cell
char2offset[thisChar] = lastOffset++;
}
// This is now last character
lastChar = thisChar;
}
// increment and get count for character
int charCount = ++counters[offset];
// This is now highestCount.
// TopChars receives current character
if (charCount > highestCount)
{
highestCount = charCount;
topChars[i] = thisChar;
}
}
}
return new string(topChars);
}
P.S. This is certainly not the best solution. But as it is significantly faster than original I thought I should help out.

Categories

Resources