C# counting characters - c#

I am trying to complete a brain teaser which has a bug and I cant find it. Just wondering if anyone knows the answer. My goal is to return the character that appears most often.
public string solution(string S)
{
int[] occurrences = new int[26];
foreach (char ch in S)
{
occurrences[ch - 'a']++;
}
char best_char = 'a';
int best_res = 0;
for (int i = 1; i < 26; i++)
{
if (occurrences[i] >= best_res)
{
best_char = (char)('a' + i);
best_res = occurrences[i];
}
}
return best_char.ToString();
}

You have small mistake. Your index should start from 0, not 1
for (int i = 0; i < 26; i++)
{
if (occurrences[i] >= best_res)
{
best_char = (char)('a' + i);
best_res = occurrences[i];
}
}
Another and safer version is that
public string Solution(string text)
{
string strResponse = string.Empty;
if (!string.IsNullOrEmpty(text))
{
List<KeyValuePair<char, int>> occurance = text.GroupBy(ch => ch)
.Where(grp => char.IsLetter(grp.Key))
.Select(grp => new KeyValuePair<char, int>(grp.Key, grp.Count()))
.OrderByDescending(c => c.Value)
.ToList();
if (occurance.Any())
strResponse = occurance.First().Key.ToString();
}
return strResponse;
}

There could actually be more than one character with the maximum number of occurrences, so:
private static Char[] GetMostFrequentChars(String text)
{
Dictionary<Char,Int32> rank = new Dictionary<Char,Int32>();
foreach (Char c in text.Where(c => !char.IsWhiteSpace(c)))
{
if (rank.ContainsKey(c))
rank[c]++;
else
rank.Add(c, 1);
}
return rank.Where(r => r.Value == rank.Values.Max()).Select(x => x.Key).ToArray();
}

If you don't care about special characters (like spaces), you could do this with LINQ:
public static GetMostFrequentCharacter(string value)
{
return value
.GroupBy(o => o)
.OrderByDescending(o => o.Count())
.First()
.Key
.ToString()
}

There are at least 2 problems:
as #Adem Çatamak says, for loop should start at index 0
ch - 'a' will throw an exception if the string contains any other character than a-z lowercase,

public static string solution(string S)
{
var charDict = new Dictionary<char, int>();
foreach (char c in S.Where(c => !char.IsWhiteSpace(c)))
{
if(!charDict.TryGetValue(c, out int count))
{
charDict[c] = 1;
}
charDict[c]++;
}
return charDict.OrderByDescending(kvp => kvp.Value).First().Key.ToString();
}
Using a dictionary and LINQ is going to be better I think. Don't just copy this code and paste it into what ever homework or class this is for, use it to learn otherwise its a waste of my time and yours really

Related

function which takes a string input and removes all the characters which occur a certain number of times

I have a word "angoora" here 'a' and 'o' occurs 2 time if user input is 2 then output should be "ngr" function should remove a and o because it occur 2 times in a string. if user enter 3 then output should be "angoora" because no character occur 3 times.
I am doing this but I think its not a right way because its not leading me towards my goal, any help would be highly appreciated.
public static SortedDictionary<char, int> Count(string stringToCount)
{
SortedDictionary<char, int> characterCount = new SortedDictionary<char, int>();
foreach (var character in stringToCount)
{
int counter = 0;
characterCount.TryGetValue(character, out counter);
characterCount[character] = counter + 1;
}
return characterCount;
}
You can use LINQs GroupBy to find the number of times each character occurs. Then remove the ones that occur the number of times you want. Something like this
public static string RemoveCharactersThatOccurNumberOfTimes(string s, int numberOfOccurances)
{
var charactersToBeRemoved = s.GroupBy(c => c).Where(g => g.Count() == numberOfOccurances).Select(g => g.Key);
return String.Join("", s.Where(c => !charactersToBeRemoved.Contains(c)));
}
You Can use this Function
static string Fix(string item, int count)
{
var chars = item.ToList().GroupBy(g => g).Select(s => new { Ch = s.Key.ToString(), Count = s.Count() }).Where(w => w.Count < count).ToList();
var characters = string.Join("", item.ToList().Select(s => s.ToString()).Where(wi => chars.Any(a => a.Ch == wi)).ToList());
return characters;
}
Your characterCount SortedDictionary is empty.
Currently you are doing:
public static SortedDictionary<char, int> Count(string stringToCount)
{
// Create a new empty SortedDictionary
SortedDictionary<char, int> characterCount = new SortedDictionary<char, int>();
// Loop through each character in stringToCount and see if SortedDictionary contains a key equal to this character (it doesn't as dictionary is empty).
foreach (var character in stringToCount)
{
int counter = 0;
characterCount.TryGetValue(character, out counter);
characterCount[character] = counter +1;
}
return characterCount;
}
Surely you want something like this:
public static SortedDictionary<char, int> Count(string stringToCount)
{
// Create a new empty SortedDictionary (use var keyword if defining variables)
var characterCount = new SortedDictionary<char, int>();
// Loop through each character and add to dictionary
foreach (var character in stringToCount)
{
// If character already in SortedDictionary.
if (characterCount.TryGetValue(character, out int count))
{
// Increment count value.
characterCount[character] = count + 1;
// Above line can also be: ++characterCount[character];
}
// Else, character not already in dictionary.
else
{
// Add character in dictionary and set count to 1.
characterCount.Add(character, 1);
}
}
return characterCount;
}
public static string foobar(string given, int number)
{
string result = given;
foreach (char c in result.Distinct())
{
if (given.Count(ch => c == ch) >= number) result= result.Replace(c.ToString(),"");
}
return result;
}
Distinct() will give you only unique characters.
Then you Count() the occurance of each unique character and remove if it is greater or equal the given number.

how to solve this logic

Write a function which takes a string input and removes all the characters which appear more than or equal to the given number.
RemoveCharacters("Spanish", 2) should return "panih"
RemoveCharacters("Spanish", 3) should return "Spanish"
string text = "Spanish";
var sb = new StringBuilder(text.Length);
int maxCount = 2;
int currentCount = 2;
char specialChar = 'S';
foreach (char c in text)
if (c != specialChar || ++currentCount <= maxCount)
sb.Append(c);
text = sb.ToString();
int commasFound = 0;
int maxCommas = 1;
text = new string(text.Where(c => c != 'S' || ++commasFound <= maxCommas).ToArray());
Console.WriteLine(text);
Let's process the string in two steps:
Find out characters to remove (which apperas more or equal than count times)
Remove such characters from the string.
Implemenattaion
private static String RemoveCharacters(string value, int count) {
if (string.IsNullOrEmpty(value))
return value;
else if (count <= 1)
return "";
HashSet<char> toRemove = new HashSet<char>(value
.GroupBy(c => char.ToUpper(c))
.Where(chunk => chunk.Count() >= count)
.Select(chunk => chunk.Key));
return string.Concat(value.Where(c => !toRemove.Contains(char.ToUpper(c))));
}
Some tests:
string[] tests = new string[] {
"Spanish",
"bla-bla-bla",
"Abracadabra",
};
string report = string.Join(Environment.NewLine, tests
.Select(test => $"{test,-15} => '{RemoveCharacters(test, 2)}'"));
Console.Write(report);
Outcome:
Spanish => 'panih' // S is removed
bla-bla-bla => '' // all characters are removed
Abracadabra => 'cd' // A, b, r are removed
I'm not writing your homework for you, but consider using a dictionary. Iterate the characters in your word. If it exists in your dictionary, increment that element. Otherwise insert it in your dictionary with a value of 1. Then iterate your dictionary keys and note which ones exceed your target. Finally, write out your string excluding those characters.

While loop for alphabet

I am trying to code the following example.
Input ABCDEFGHIJKLMNOPQRSTUVWXYZ
Output ZYXWVUTSRQPONMLKJIHGFEDCBA
If user types in A it will output Z. It has to go past 25 characters to reach Z. So I am guessing a while loop will be needed, then if B it has to go through 23 times, so – 2 and so on until it reaches M as it will skip though 1 to reach N, then start again at 25.
Any suggestion on how to approach this?
Capital ASCII characters range according to the ASCII-table from 65 (0x41, 'A') to 90 (0x5A, 'Z').
This is the algorithm:
// inputChar is a char holding your character
char inputChar = getCharFromUser();
int inputVal = inputChar - 65; // e.g. 0 for 'A', 1 for 'B'
char outputChar = 90 - inputVal; // e.g. 90 - 1 = 89 = 'Y'
outputCharToUser(outputChar);
And this is how you might implement it in C#:
while (true)
{
var key = Console.ReadKey(intercept: true);
var inputChar = char.ToUpper(key.KeyChar);
var outputChar = (char)('Z' - inputChar + 'A');
Console.Write("{0}={1} ", inputChar, outputChar);
}
You could use two dictionaries which enable to lookup the char from index and vice-versa:
var indexLookup = "abcdefghijklmnopqrstuvwxyz"
.Select((chr, index) => new { chr, index })
.ToDictionary(x => x.chr, x => x.index);
var charLookup = "abcdefghijklmnopqrstuvwxyz"
.Select((chr, index) => new { chr, index })
.ToDictionary(x => x.index, x => x.chr);
Now it's simple, the essential part is charLookup[25 - indexOfChar]:
string userInput = "B";
bool isUpper = char.IsUpper(userInput[0]);
char inputChar = Char.ToLowerInvariant(userInput[0]);
if(indexLookup.ContainsKey(inputChar))
{
int indexOfChar = indexLookup[inputChar];
char oppositeChar = charLookup[25 - indexOfChar];
string result = isUpper ? Char.ToUpperInvariant(oppositeChar).ToString() : oppositeChar.ToString();
Console.Write(result); // Y
}
Actually you don't need two dictionaries but only one since the string can already be used to lookup a char by index. Here is a class which provides the logic:
public class CharSwap
{
private string alphabet;
private Dictionary<char, int> indexLookup;
public CharSwap() : this("abcdefghijklmnopqrstuvwxyz") { }
public CharSwap(string alphabet)
{
if(alphabet == null) throw new ArgumentNullException("alphabet");
this.alphabet = alphabet;
indexLookup = alphabet.Select((chr, index) => new { chr, index }).ToDictionary(x => x.chr, x => x.index);
}
public char? OppositeChar(char input)
{
char lowerChar = Char.ToLowerInvariant(input);
if (!indexLookup.ContainsKey(lowerChar))
return null;
int indexOfChar = indexLookup[lowerChar];
int indexOpposite = alphabet.Length - 1 - indexOfChar;
return Char.IsUpper(input)
? Char.ToUpperInvariant(alphabet[indexOpposite])
: alphabet[indexOpposite];
}
}
Test:
CharSwap cw = new CharSwap();
char? oppositeChar = cw.OppositeChar('B');
Console.Write(oppositeChar);
char input = 'B';
string Range = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char result = Range[Range.Length - 1 - Range.IndexOf(input)]; //Y
or maybe another approach
char input = 'B';
string Range = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char result = Range.Reverse().ElementAt(Range.IndexOf(input)); //Y
How about something like this?
char[] alphabet = {'A','B', 'C'} // and so on
char[] mapsTo = {'Z', 'Y', 'X'} // and so on, excluded for brevity
public function string changeLetter(char input)
{
int i = 0;
foreach (char c in alphabet) {
if (c == input) {
return mapsTo[i];
}
i++;
}
return '';
}
Converted to c#:
char[] alphabet = {'A','B', 'C'}; // and so on
char[] mapsTo = {'Z', 'Y', 'X'}; // and so on, excluded for brevity
public string changeLetter(char input)
{
int i = 0;
foreach (char c in alphabet) {
if (c == input) {
return mapsTo[i].ToString();
}
i++;
}
return default(char).ToString();
}
You would call this function like this (for instance):
public static void RunProgram()
{
Console.WriteLine("Please type in character");
input = Console.ReadKey().KeyChar;
Console.WriteLine("You typed in " + input + ". This results in: " + ChangeInput(input));
}
... where "ChangeInput" is the function defined earlier.
The easy way to solve this is to use a Dictionary<char, char>:
public class Atbash {
static string source = "abcdefghijklmnopqrstuvwxyz";
static List<char> keys = source.ToList();
static List<char> values = source.Reverse().ToList();
static Dictionary<char, char> Converter = keys.ToDictionary(x => x, x => values[keys.IndexOf(x)]);
public static char Convert(char input)
{
char output;
bool isUpper = char.IsUpper(input);
input = char.ToLowerInvariant(input);
if(Converter.ContainsKey(input)) {
output = Converter[input];
return (isUpper) ? char.ToUpperInvariant(output) : output;
}
throw new ArgumentOutOfRangeException("Input char is unknown");
// of course, it can return default(char) instead of throwing an exception.
}
}
Why Atbash? read about it here.

C# Display repeated letter in string

I'm trying to figure out how to display the repeated letter in a string. For example if the entered string was "red house" it would show that the letter "e" was repeated, then it would be displayed in the label I created. This is a basic program, Here is what I've written thus far. Any help is appreciated.
private void button1_Click(object sender, EventArgs e)
{
string enteredWord = textBox1.Text;
char letter;
for (int index = 0; index < enteredWord.Length; index++)
{
letter = enteredWord[index];
if (letter == enteredWord[index])
{
label1.Text = (letter.ToString());
}
else
{ return;
}
You could also use Linq for that:
var query = from l in enteredWord
group l by l into g
where g.Count() > 1
select new { letter = g.Key, count = g.Count() };
foreach (var item in query)
{
label1.Text += item.letter + " ";
}
This should do what you're looking for:
public static Dictionary<char, int> Count(string input)
{
Dictionary<char, int> d = new Dictionary<char, int>();
foreach (char c in input)
{
if (d.Keys.Contains(c))
d[c]++;
else
d.Add(c, 1);
}
return d;
}
static void Main(string[] args)
{
Dictionary<char, int> d = Count("Red House");
foreach (char c in d.Keys)
{
Console.WriteLine("{0}: {1}", c, d[c]);
}
Console.ReadKey();
}
Could build a HashSet and check each letter. I'm sure there's a more efficient way, but this should work: (untested)
string enteredWord = textBox1.Text;
HashSet<char> letters = new HashSet<char>();
foreach(char c in enteredWord)
{
if (letters.Contains(c))
label1.Text += c.ToString();
else
letters.Add(c);
}
EDIT: I suppose this will print out duplicates of the letters if they appear 3 or more times, but you get the idea.
I would suggest using a List and add the value if you have not encountered it, and update the textbox if you have already encountered it. For a future FYI, you could use a Dictionary if you need to know the exact counts, also.
List<char> charactersThatHaveOccurred = new List<char>();
string enteredWord = textBox1.Text;
foreach(var character in enteredWord)
{
if(charactersThatHaveOccurred.Contains(character ))
label1.Text += character ;
else
charactersThatHaveOccurred.Add(character );
}
The first thing that comes to mind is:
List<char> repeats = enteredWord.Where(c1 => enteredWord.Count(c2 => c1 == c2) > 1).Distinct().ToList();
That will return a List<char> of all the repeated characters. You can grab the first one, or whatever you want.
It may not be optimal in terms of speed, but it's simple.
See other answers for better ways to solve this problem, but I'm trying to see what you were trying to do. (Note, the code below is very inefficient, using a HashSet of already seen characters would be my solution at it.)
Perhaps you're missing an inner for loop? Currently you assign something (enteredword[index]) to letter, and then immediately compare them. So you're comparing each letter to itself.
something like
for (int index = 0; index < enteredWord.Length; index++)
{
letter = enteredWord[index];
for (int index2 = 0; index < enteredWord.Length; index++)
{
if (index != index2 && letter == enteredWord[index2])
{
label1.Text = (letter.ToString());
return;
}
}
}
string s = "red house";
foreach (char c in s)
{
if (s.IndexOf(c) != s.LastIndexOf(c))
{
label1.Text += c.ToString();
}
s.Replace(c.ToString(), string.Empty);
}

How to get continuous characters in C#?

I've a
List<String> MyList=new List<string>();
I need to fill the list MyList with n values.
if the value of n is 2 then the list MyList will contain
"A","B"
if 10 then
"A","B","C"....."J"
if 30 then
"A"....."Z","AA","AB",AC","AD"
if 1000 then
"A",....."Z","AA","AB"......"AZ","BA","BB"......."BZ"........"YZ","AAA",AAB".....
and so on
I do not know how to do this.
Please help me to do this using any method Using LINQ or LAMBDA Expression
Edit 2:
This is probably the easiest way to implement it. I tested it, it works fine. You could generate a infinite number of strings.
public IEnumerable<string> GenerateStrings()
{
foreach(string character in Alphabet())
{
yield return character;
}
foreach (string prefix in GenerateStrings())
{
foreach(string suffix in Alphabet())
{
yield return prefix + suffix;
}
}
}
public IEnumerable<string> Alphabet()
{
for(int i = 0; i < 26; i++)
{
yield return ((char)('A' + i)).ToString();
}
}
Stuff I wrote before:
You could also write a little recursive function which returns any string by a certain index. This may not be optimal performance wise, because there are some repetitive divisions, but it may be fast enough for your purpose.
It is quite short and easy:
string GetString(int index)
{
if (index < 26)
{
return ((char)('A' + index)).ToString();
}
return GetString(index / 26 - 1) + GetString(index % 26);
}
usage (may also be put into another method:
List<string> strings = Enumerable.Range(0, 1000)
.Select(x => GetString(x))
.ToList();
This is working code, just wrote a test for it.
Edit: eg, the "full linq way" application of GetString:
public void IEnumerale<string> GenerateStrings()
{
int index = 0;
// generate "infinit" number of values ...
while (true)
{
// ignoring index == int.MaxValue
yield return GetString(index++);
}
}
List<string> strings = GenerateStrings().Take(1000).ToList();
I did something similar in SQL a while back.
Translated to C# this is a function to create a code from a number:
public static string GetCode(int id) {
string code, chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (id <= chars.Length) {
code = chars.Substring(id - 1, 1);
} else {
id--;
int value = chars.Length, adder = 0;
while (id >= value * (chars.Length + 1) + adder) {
adder += value;
value *= chars.Length;
}
code = chars.Substring((id - adder) / value - 1, 1);
id = ((id - adder) % value);
while (value > 1) {
value /= chars.Length;
code += chars.Substring(id / value, 1);
id = id % value;
}
}
return code;
}
Then you just get numbers from 1 and up, and translate into codes:
var codes = Enumerable.Range(1, 1000).Select(n => GetCode(n));
The limit of the function is currently "ZZZZZZ" or 321272406. (After that you get a division by zero.)
Note that this function uses all combinations and returns "A".."Z", "AA".."ZZ", "AAA"..."ZZZ" rather than starting at "AB" and "ABC".
This is similar to this question (but not quite enough to mark it as a duplicate, and it's a hard problem to search for anyway).
Use any of the working IEnumerable<string> answers (or at least, any which cover the range you need), and then if you need to create a list with a certain number of elements, just use:
List<string> list = GenerateSequence().Take(count).ToList();
This code is working fine, but I'm not sure if it's "LINQ enough".
char[] validChars = Enumerable.Range(0, 26).Select(i => (char)('A' + i)).ToArray();
List<string> result = new List<string>();
List<string> generator = validChars.Select(ch => ch.ToString()).ToList();
int n = 1000;
while (result.Count < n)
{
result.AddRange(generator);
generator = generator.Take((n - result.Count) / validChars.Length + 1)
.SelectMany(s => validChars.Select(ch => s + ch))
.ToList();
}
var output = result.Take(n);
Try the below .. I am using Cross Join and a Union to build the source and then filtering the record by using the Take extension method
char[] charArray = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
List<String> MyList = new List<string>();
int n = 1000;
(from value1 in charArray
select new
{
newString = value1.ToString()
})
.Union
(
(from value1 in charArray
from value2 in charArray
select new
{
newString = string.Concat(value1, value2)
})
)
.Union
(
(from value1 in charArray
from value2 in charArray
from value3 in charArray
select new
{
newString = string.Concat(value1, value2, value3)
})
)
.Take(n)
.ToList()
.ForEach(i => MyList.Add(i.newString));
Hope this will give you some idea of using a combination of Linq,Lambda and Extension method.
#DannyChen this is it. your code with a little changes..
char[] validChars = Enumerable.Range(0, 26).Select(i => (char)('A' + i)).ToArray();
int n = 30;
int pointer = 0;
int pointerSec = 0;
int Deg = 0;
string prefix = string.Empty;
string prefixMore = string.Empty;
List<string> result = new List<string>();
while (n > 0)
{
result.AddRange(validChars.Skip(pointer).Select(ch => prefix + ch).Take(n));
if (pointer == 26)
{
pointer = -1;
Deg += 1;
prefixMore = "" + validChars[pointerSec];
pointerSec++;
n++;
}
else
{
if (Deg == 0)
{
prefix = "" + validChars[pointer];
}
else
{
prefix = prefixMore + validChars[pointer];
}
}
n--;
pointer++;
}
it is 100% correct.

Categories

Resources