This is the question:
Write a program that reads a string from the console and prints in alphabetical order all letters from the input string and how many times each one of them occurs in the string.
It seemed interesting and not too complicated at first, but I couldn't solve it.
public static void Letters()
{
string input;
Console.Write("Enter a string: ");
input = Console.ReadLine();
var chars = new List<char>();
//To populate characters with the letters of the input but without repetition
for(int index = 0; index < input.Length; index++)
{
if(!characters.Contains(input[index]))
characters.Add(input[index]);
}
//To increment the counter corresponding to the character index
int[] counter = new int[characters.Count];
//Now what ?!
}
My thinking is:
I create a collection to hold the letters of the input string, without any repetition.
Then I use an int array of the same size such that each int holds the number of times the corresponding letter has occurred in the input string.
I not only don't know how to implement this, but I have a feeling its not an ideal solution
to the problem. There's probably a query or a lambda expression that should make this easy
to implement and read.
Note: The question following this is of the same nature. The difference is that it asks
to replace the repeated letters with a single one "aaabbbccc" to "abc".
I will appreciate if the logic is described. I will try to implement it on my own,
just point me to the logic.
EDIT:
This my answer using a dictionary
public static void Letters()
{
string input;
Console.Write("Enter a string: ");
input = Console.ReadLine();
var dict = new Dictionary<char, int>();
for(int index = 0; index < input.Length; index++)
{
char theKey = input[index]; //just for clarity
if(!dict.ContainsKey(theKey))
dict.Add(theKey, 1);
else
dict[input[index]]++;
}
foreach(var key in dict.Keys)
{
Console.WriteLine("{0}\t{1}", key, dict[key]);
}
Dictionnary<String, int>
Key = string = letter IE a,b,c,d,e,f.....
Int is number of occurence
So start by doing this :
Dictionnary.add(a,0)
...
Dictionnary.add(z,0);
And then read the string and do this
Dictionnary[letterFound ] += 1;
There is a better way knowing what is the value in ASCi of each letter to init the dictionnary, but i don't think is mandatory for such exercice.
Good luck
var myString = "Hello";
var dict = new Dictionary<char, int>();
foreach(var c in myString)
{
if(!dict.ContainsKey(c))
dict.Add(c, 1);
else
dict[c]++;
}
var orderedDict = dict.OrderBy(x => x.Key);
foreach(var kvp in orderedDict)
{
Console.WriteLine("Letter: {0}, Times: {1}", kvp.Key, kvp.Value);
}
For simple and readable solution use LINQ, GroupBy and anonymous types
string input = Console.ReadLine();
var groupedLettersOrdered = input.GroupBy(x => x, (character, charCollection) =>
new {Character = character, Count = charCollection.Count()})
.OrderBy(x => x.Character);
foreach(var letterGroup in groupedLettersOrdered)
Console.WriteLine("Character {0}, Count: {1}", letterGroup.Character, letterGroup.Count);
However Dictionary<char, int> solution will be (should be) faster and better for large strings
Consider first that a character has a binary representation (sequence of 1s and 0s) just like a scalar value. Consider also that for a Latin alphabet like English, the alphabetical order and numerical order of their equivalents correspond.
So... you could do something like this:
define an array of ints of a size large enough to accommodate all possible character values (arbitrarily, we could make it 256 for a UTF-8 string).
iterate over each character in the string; for each character, convert the character to its integer equivalent, use that as an index into the array and increment the value at that index.
iterate over the array and for each non-zero element, print out the character equivalent of the array index and the contents of the element (character count)
string myString = "the quick brown fox jumps over the lazy dog";
byte[] bytes = Encoding.UTF8.GetBytes(myString);
int[] counts = new int[256];
foreach (var b in bytes)
{
counts[(int)b]++;
}
for (int i = 0; i < 256; i++)
{
if (counts[i] > 0)
{
Console.WriteLine("{0} - {1}", (char)(byte)i, counts[i]);
}
}
The above solution can easily be generalized to disregard case by performing GetBytes on myString.ToUpper(). To generalize to Unicode would be a little more work because you'd have to pair up the bytes in proper endian order.
Related
I have a list of items, each with numbers, followed by a space, and then a word. Think scrabble.
36 adore
36 adore
27 amigo
31 amino
28 amiss
I am trying to use the 2 digit number as an organizational item to which I can rank the words by order of value.
My list, ComJoined is shown above.
My Code is:
for (int i = 0; i < ComJoined.Count; i++)
{
if (i + 1 <= ComJoined.Count)
{
int one = (Convert.ToInt32(ComJoined[i].Substring(0, 2)));
int two = Convert.ToInt32(ComJoined[i + 1].Substring(0, 2));
if (one <= two)
{
string Stuff = ComJoined[i];
ComJoined.Insert(i + 1, Stuff);
ComJoined.RemoveAt(i);
}
}
}
For some reason it says that "Input string was not in a correct format." I read that this meant the string didn't have a int value, but the part being converted, the first two digits, obviously do. Why is this occurring?
So you want to sort the list descending, according to the 2 digit code, and all items start with the two digit code?
This would just be a linq one-liner: var sortedList = ComJoined.OrderByDescending().ToList()
This might be less complex of a solution to your problem:
var words = new SortedDictionary<int, string>();
foreach (var com in ComJoined)
{
string[] splitCom = com.Split(' ');
// Assuming your data is in the correct format. You could use TryParse to avoid an exception.
words.Add(int.Parse(splitCom[0]), splitCom[1]);
}
// Do something with the sorted dictionary...
foreach (KeyValuePair<int, string> word in words)
Console.WriteLine("{0} {1}", word.Key, word.Value);
Using C# I'm trying to find a specific word within a char array. Also, I don't want the same letter used more than once i.e. the word is 'hello' and I'm trying to find it within a random array of letters, so if the letter 'l' is used out of the random array of letters, I don't want it to be used again. There should be another 'l' within the array of letters to be used as the second 'l' in "hello". Just trying to be precise. A simple answer would be very helpful. Thank you.
Here is my attempt so far.
public static char [] Note = "hello".ToCharArray();
public static char [] Newspaper = "ahrenlxlpoz".ToCharArray();
static void main(string[] args)
{
Array.Sort(Note);
Array.Sort(Newspaper);
if(Newspaper.Contains<Note>)
{
Console.Write("It should display the letters of Note found within Newspaper");
}
}
I assume by "contains" you mean Newspaper has enough number of letters from each letter to make up Note. For example, you need at least two l's to make up the word "hello". If so, you need to basically count the number of each letter in both strings, and make sure the number of each letter in Note is less than or equal to the number of that letter in Newspaper.
var dictNote = Note.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count());
var dictNews = Newspaper.GroupBy(c => c).ToDictionary(g => g.Key, g => g.Count());
bool contains = dictNote.All(x =>
dictNews.ContainsKey(x.Key) && x.Value <= dictNews[x.Key]);
In fact, a string is a char array. And the most "classic" way to do this would be:
string Note = "hello";
char[] Newspaper = "ahrenlxlpoz".ToCharArray();
string res = "";
for (int i = 0; i < Note.Length; i++)
for (int j = 0; j < Newspaper.Length; j++)
if (Note[i] == Newspaper[j])
{
res += Newspaper[j];
Newspaper[j] = ' ';
break;
}
//This prints the remaining characters in Newspaper. I avoid repeating chars.
for (int i = 0; i < Newspaper.Length; i++ )
Console.Write(Newspaper[i]+"\n");
Console.Write("\n\n");
if (Note.Equals(res)) Console.Write("Word found");
else Console.Write("Word NOT found");
Console.Read();
At the end, res will be "hello". Print res in the console. I added the ' ' to avoid repeated characters as someone said in the answer up. So at the end it will compare the result with the word and will tell you if it found the word in the string. Try changing Newspaper to this: "ahrenlxlpaz" and it will tell you the word is NOT found :)
Try this:
public static char[] Note = "hello".ToCharArray();
public static char[] Newspaper = "ahrenlxlpoz".ToCharArray();
foreach (char c in Note) //check each character of Note
{
if (Newspaper.Contains(c))
{
Console.Write(c); //it will display hello
}
}
I'm making a program in winforms application where in it generates random patterns with seven length of characters such as 2Vowels-5consonants, 3Vowels-4Consonants and so on..after which it generates random letters specific to the pattern generated..
After the letters are generated, I want to list all possible combinations of letters to that generated letters.. and try to check if the generated combinations are present on the system's dictionary..
-Sample Input-
Pattern : 3V-4C Letters: AIOLMNC
Combinations: AIO AOL OIL .... MAIL
.... CLAIM .... and so on...
-Output-
Words Found: OIL MAIL CLAIM ... and so on...
This program is intended for word games.. I'm asking for help and any suggestions that may help me to solve my problem. I can't think of proper way to start the algorithm and how to code it..
I don't normally do this, but I came up with an even better solution for your problem, and it deserves its own answer! This AnagramSolver solution is WAY more optimized than my other answer, because it doesn't create every-single-permutation of a word, and dictionary lookups are very optimized. Try it out:
Usage Example:
string[] dictionary = ReadDictionary(...);
var solver = new AnagramSolver(dictionary);
int minimumLength = 1;
IEnumerable<string> results = solver.SolveAnagram("AEMNS", minimumLength);
// Output the results:
foreach (var result in results)
{
Console.WriteLine(result);
}
// Output example:
// "NAMES", "MANES", "MEANS", "AMEN", "MANE", "MEAN", "NAME", "MAN", "MAE", "AM", "NA", "AN", "MA", "A",
Code:
public class AnagramSolver
{
public AnagramSolver(IEnumerable<string> dictionary)
{
// Create our lookup by keying on the sorted letters:
this.dictionary = dictionary.ToLookup<string, string>(SortLetters);
}
private ILookup<string, string> dictionary;
public IEnumerable<string> SolveAnagram(string anagram, int minimumLength)
{
return CreateCombinations(anagram, minimumLength)
// Sort the letters:
.Select<string, string>(SortLetters)
// Make sure we don't have duplicates:
.Distinct()
// Find all words that can be made from these letters:
.SelectMany(combo => dictionary[combo])
;
}
private static string SortLetters(string letters)
{
char[] chars = letters.ToCharArray();
Array.Sort(chars);
return new string(chars);
}
/// <summary> Creates all possible combinations of all lengths from the anagram. </summary>
private static IEnumerable<string> CreateCombinations(string anagram, int minimumLength)
{
var letters = anagram.ToCharArray();
// Create combinations of every length:
for (int length = letters.Length; length >= minimumLength; length--)
{
yield return new string(letters, 0, length);
// Swap characters to form every combination:
for (int a = 0; a < length; a++)
{
for (int b = length; b < letters.Length; b++)
{
// Swap a <> b if necessary:
char temp = letters[a];
if (temp != letters[b]) // reduces duplication
{
letters[a] = letters[b];
letters[b] = temp;
yield return new string(letters, 0, length);
}
}
}
}
}
}
Here's a summary of the algorithm:
The basic idea is that every set of anagrams derive from the same set of letters.
If we sort the letters, we can group together sets of anagrams.
I got this idea from Algorithm for grouping anagram words.
For example, a set of anagrams ("NAMES", "MANES", "MEANS") can be keyed on "AEMNS".
Therefore, once we create our dictionary lookup, it's incredibly easy and fast to solve the anagram -- simply sort the letters of the anagram and perform the lookup.
The next challenge is to find all "smaller" anagrams -- for example, finding "NAME", "SANE", "MAN", "AN", "A", etc.
This can be done by finding all combinations of the anagram.
Combinations are much easier to find than permutations. No recursion is needed. I implemented complete combinations with 3 loops and a simple swap! It took a while to get the algorithm right, but now that it's cleaned up, it's very pretty.
For each combination found, we must again sort the letters and perform the lookup.
This gives us all possible solutions to the anagram!
Update
This solution directly answers your question ("How do I form all combinations of characters"), but this is not a very efficient way to solve anagrams. I decided to create a better solution for solving anagrams, so please see my other answer.
This sounds like a fun puzzle.
To begin, here's how you can create your "random" inputs:
Random rng = new Random();
const string vowels = "AEIOU";
const string consonants = "BCDFGHJKLMNPQRSTVWXYZ";
string CreatePuzzle(int vowelCount, int consonantCount){
var result = new StringBuilder(vowelCount + consonantCount);
for (int i = 0; i < vowelCount; i++) {
result.Append(vowels[rng.Next(5)]);
}
for (int i = 0; i < consonantCount; i++) {
result.Append(consonants[rng.Next(21)]);
}
return result.ToString();
}
Then you'll need to create all permutations of these letters. This is a great job for recursion. The following code is an implementation of Heap's Algorithm that I found at http://www.cut-the-knot.org/do_you_know/AllPerm.shtml. Another helpful resource is http://www.codeproject.com/KB/recipes/Combinatorics.aspx
/// <summary>
/// Returns all permutations of the puzzle.
/// Uses "Heap's Algorithm" found at http://www.cut-the-knot.org/do_you_know/AllPerm.shtml
/// </summary>
IEnumerable<string> CreatePermutations(string puzzle) {
// It is easier to manipulate an array; start off the recursion:
return CreatePermutations(puzzle.ToCharArray(), puzzle.Length);
}
IEnumerable<string> CreatePermutations(char[] puzzle, int n) {
if (n == 0) {
// Convert the char array to a string and return it:
yield return new string(puzzle);
} else {
// Return the sub-string:
if (n < puzzle.Length) {
yield return new string(puzzle, n, puzzle.Length - n);
}
// Create all permutations:
for (int i = 0; i < n; i++) {
// Use recursion, and pass-through the values:
foreach (string perm in CreatePermutations(puzzle, n-1)) {
yield return perm;
}
// Create each permutation by swapping characters: (Heap's Algorithm)
int swap = (n % 2 == 1) ? 0 : i;
char temp = puzzle[n-1];
puzzle[n-1] = puzzle[swap];
puzzle[swap] = temp;
}
}
}
Note that this algorithm doesn't check for duplicates, so an input like "AAA" will still result in 6 permutations. Therefore, it might make sense to call .Distinct() on the results (although the CodeProject article has an algorithm that skips duplicates, but is more complicated).
The final step, as you stated, is to check all permutations against your dictionary.
Optimizations
This solution is fairly simple, and will probably work really well if your puzzles remain small. However, it is definitely a "brute force" kind of method, and as the puzzle gets bigger, performance drops exponentially!
I'm currently making a game but I seem to have problems reading values from a text file. For some reason, when I read the value, it gives me the ASCII code of the value rather than the actual value itself when I wrote it to the file. I've tried about every ASCII conversion function and string conversion function, but I just can't seem to figure it out.
I use a 2D array of integers. I use a nested for loop to write each element into the file. I've looked at the file and the values are correct, but I don't understand why it's returning the ASCII code. Here's the code I'm using to write and read to file:
Writing to file:
for (int i = 0; i < level.MaxRows(); i++)
{
for (int j = 0; j < level.MaxCols(); j++)
{
fileWrite.Write(level.GetValueAtIndex(i, j) + " ");
//Console.WriteLine(level.GetValueAtIndex(i, j));
}
//add new line
fileWrite.WriteLine();
}
And here's the code where I read the values from the file:
string str = "";
int iter = 0; //used to iterate in each column of array
for (int i = 0; i < level.MaxRows(); i++)
{
iter = 0;
//TODO: For some reason, the file is returning ASCII code, convert to int
//keep reading characters until a space is reached.
str = fileRead.ReadLine();
//take the above string and extract the values from it.
//Place each value in the level.
foreach (char id in str)
{
if (id != ' ')
{
//convert id to an int
num = (int)id;
level.ChangeTile(i, iter, num);
iter++;
}
}
This is the latest version of the loop that I use to read the values. Reading other values is fine; it's just when I get to the array, things go wrong. I guess my question is, why did the conversion to ASCII happen? If I can figure that out, then I might be able to solve the issue. I'm using XNA 4 to make my game.
This is where the convertion to ascii is happening:
fileWrite.Write(level.GetValueAtIndex(i, j) + " ");
The + operator implicitly converts the integer returned by GetValueAtIndex into a string, because you are adding it to a string (really, what did you expect to happen?)
Furthermore, the ReadLine method returns a String, so I am not sure why you'd expect a numeric value to magically come back here. If you want to write binary data, look into BinaryWriter
This is where you are converting the characters to character codes:
num = (int)id;
The id variable is a char, and casting that to int gives you the character code, not the numeric value.
Also, this converts a single character, not a whole number. If you for example have "12 34 56 " in your text file, it will get the codes for 1, 2, 3, 4, 5 and 6, not 12, 34 and 56.
You would want to split the line on spaces, and parse each substring:
foreach (string id in str.Split(' ')) {
if (id.Length > 0) {
num = Int32.Parse(id);
level.ChangeTile(i, iter, num);
iter++;
}
}
Update: I've kept the old code (below) with the assumption that one record was on each line, but I've also added a different way of doing it that should work with multiple integers on a line, separated by a space.
Multiple records on one line
str = fileRead.ReadLine();
string[] values = str.Split(new Char[] {' '});
foreach (string value in values)
{
int testNum;
if (Int32.TryParse(str, out testnum))
{
// again, not sure how you're using iter here
level.ChangeTile(i, iter, num);
}
}
One record per line
str = fileRead.ReadLine();
int testNum;
if (Int32.TryParse(str, out testnum))
{
// however, I'm not sure how you're using iter here; if it's related to
// parsing the string, you'll probably need to do something else
level.ChangeTile(i, iter, num);
}
Please note that the above should work if you write out each integer line-by-line (i.e. how you were doing it via the WriteLine which you remarked out in your code above). If you switch back to using a WriteLine, this should work.
You have:
foreach (char id in str)
{
//convert id to an int
num = (int)id;
A char is an ASCII code (or can be considered as such; technically it is a unicode code-point, but that is broadly comparable assuming you are writing ANSI or low-value UTF-8).
What you want is:
num = (int)(id - '0');
This:
fileWrite.Write(level.GetValueAtIndex(i, j) + " ");
converts the int returned from level.GetValueAtIndex(i, j) into a string. Assuming the function returns the value 5 for a particular i and j then you write "5 " into the file.
When you then read it is being read as a string which consists of chars and you get the ASCII code of 5 when you cast it simply to an int. What you need is:
foreach (char id in str)
{
if (id != ' ')
{
//convert id to an int
num = (int)(id - '0'); // subtract the ASCII value for 0 from your current id
level.ChangeTile(i, iter, num);
iter++;
}
}
However this only works if you only ever are going to have single digit integers (only 0 - 9). This might be better:
foreach (var cell in fileRead.ReadLine().Split(' '))
{
num = Int.Parse(cell);
level.ChangeTile(i, iter, num);
iter++;
}
First of all, there is actually more restrictions than stated in the title. Plz readon.
say, i have a dictionary<char,int> where key acts as the item, and value means the number of occurrence in the output. (somewhat like weighting but without replacement)
e.g. ('a',2) ('b',3) ('c',1)
a possible output would be 'babcab'
I am thinking of the following way to implement it.
build a new list containing (accumulated weightings,char) as its entry.
randomly select an item from the list,
recalculate the accumulated weightings, also set the recent drawn item weighing as 0.
repeat.
to some extent there might be a situation like such: 'bacab' is generated, but can do no further (as only 'b' left, but the weighting is set to 0 as no immediate repetition allowed). in this case i discard all the results and start over from the very beginning.
Is there any other good approach?
Also, what if i skip the "set the corresponding weighting to 0" process, instead I reject any infeasible solution. e.g. already i got 'bab'. In the next rng selection i get 'b', then i redo the draw process, until i get something that is not 'b', and then continue. Does this perform better?
How about this recursive algorithm.
Create a list of all characters (candidate list), repeating them according to their weight.
Create an empty list of characters (your solution list)
Pick a random entry from the candidate list
If the selected item (character) is the same as the last in solution list then start scanning for another character in the candidate list (wrapping around if needed).
If no such character in step 4 can be found and candidate list is not empty then backtrack
Append the selected character to the solution list.
If the candidate list is empty print out the solution and 'backtrack', else go to step 3.
I'm not quite sure about the 'backtrack' step yet, but you should get the general idea.
Try this out, it should generate a (pseudo) random ordering of the elements in your enumerable. I'd recommend flattening from your dictionary to a list:
AKA Dictionary of
{b, 2}, {a, 3} becomes {b} {b} {a} {a} {a}
public static IEnumerable<T> RandomPermutation<T>(this IEnumerable<T> enumerable)
{
if (enumerable.Count() < 1)
throw new InvalidOperationException("Must have some elements yo");
Random random = new Random(DateTime.Now.Millisecond);
while (enumerable.Any())
{
int currentCount = enumerable.Count();
int randomIndex = random.Next(0, currentCount);
yield return enumerable.ElementAt(randomIndex);
if (randomIndex == 0)
enumerable = enumerable.Skip(1);
else if (randomIndex + 1 == currentCount)
enumerable = enumerable.Take(currentCount - 1);
else
{
T removeditem = enumerable.ElementAt(randomIndex);
enumerable = enumerable.Where(item => !item.Equals(removeditem));
}
}
}
If you need additional permutations, simply call it again for another random ordering. While this wont get you every permutation, you should find something useful. You can also use this as a base line to get a solution going.
This should be split into some seperate methods and could use some refactoring but the idea is to implement it in such a way that it does not depend on randomly moving things around till you get a valid result. That way you can't predict how long it would take
Concatenate all chars to a string and randomize that string
Loop through the randomized string and find any char that violates the rule
Remove that char from the string
Pick a random number. Use this number as "put the removed char at the nth valid position")
Loop around the remaining string to find the Nth valid postion to put the char back.
If there is no valid position left drop the char
Repeat from step 2 until no more violations are found
using System;
using System.Collections.Generic;
namespace RandomString
{
class Program
{
static void Main(string[] args)
{
Random rnd = new Random(DateTime.Now.Millisecond);
Dictionary<char, int> chars = new Dictionary<char, int> { { 'a', 2 }, { 'b', 3 }, { 'c', 1 } };
// Convert to a string with all chars
string basestring = "";
foreach (var pair in chars)
{
basestring += new String(pair.Key, pair.Value);
}
// Randomize the string
string randomstring = "";
while (basestring.Length > 0)
{
int randomIndex = rnd.Next(basestring.Length);
randomstring += basestring.Substring(randomIndex, 1);
basestring = basestring.Remove(randomIndex, 1);
}
// Now fix 'violations of the rule
// this can be optimized by not starting over each time but this is easier to read
bool done;
do
{
Console.WriteLine("Current string: " + randomstring);
done = true;
char lastchar = randomstring[0];
for (int i = 1; i < randomstring.Length; i++)
{
if (randomstring[i] == lastchar)
{
// uhoh violation of the rule. We pick a random position to move it to
// this means it gets placed at the nth location where it doesn't violate the rule
Console.WriteLine("Violation at position {0} ({1})", i, randomstring[i]);
done = false;
char tomove = randomstring[i];
randomstring = randomstring.Remove(i, 1);
int putinposition = rnd.Next(randomstring.Length);
Console.WriteLine("Moving to {0}th valid position", putinposition);
bool anyplacefound;
do
{
anyplacefound = false;
for (int replace = 0; replace < randomstring.Length; replace++)
{
if (replace == 0 || randomstring[replace - 1] != tomove)
{
// then no problem on the left side
if (randomstring[replace] != tomove)
{
// no problem right either. We can put it here
anyplacefound = true;
if (putinposition == 0)
{
randomstring = randomstring.Insert(replace, tomove.ToString());
break;
}
putinposition--;
}
}
}
} while (putinposition > 0 && anyplacefound);
break;
}
lastchar = randomstring[i];
}
} while (!done);
Console.WriteLine("Final string: " + randomstring);
Console.ReadKey();
}
}
}