Get Occurrences of Letters in A String - c#

I am trying to count occurrences of letters in a string and almost got the result using the below code snippet:
public static void GetNoofLetters()
{
string str = "AAAAABBCCCDDDD";
int count = 1;
char[] charVal = str.ToCharArray();
List<string> charCnt = new List<string>();
string concat = "";
//Getting each letters using foreach loop
foreach (var ch in charVal)
{
int index = charCnt.FindIndex(c => c.Contains(ch.ToString())); //Checks if there's any existing letter in the list
if(index >= 0) //If letter exists, then count and replace the last value
{
count++;
charCnt[charCnt.Count - 1] = count.ToString() + ch.ToString();
}
else
{
charCnt.Add(ch.ToString()); //If no matching letter exists, then add it to the list initially
count = 1;
}
}
foreach (var item in charCnt)
{
concat += item;
}
Console.WriteLine(concat.Trim());
}
The code works for the given input sample and returns output as: 5A2B3C4D. Simple is that.
But say I've the following input: Second input sample
string str = "AAAAABBCCCDDDDAA";
Expected output:
5A2B3C4D2A
With the above code that I've returns the output as follows:
5A2B3C6A
The above actually occurred for the below code snippet:
if(index >= 0) //If letter found, then count and replace the last value
{
count++;
charCnt[charCnt.Count - 1] = count.ToString() + ch.ToString();
}
Is there any better idea that I can resolve to get the expected output for the second input sample? I can understand, am close enough and may be missing something that's simple enough.
Code sample: Count Occurrences of Letters

Why don't we just loop over value and count? We can have two possibilities:
When character c doesn't equal to current (we have the different character) we should write down the previous sequence and start a new one
Otherwise, add 1 to count
Code:
private static string Compress(string value) {
if (string.IsNullOrEmpty(value))
return value;
char current = '\0';
int count = 0;
StringBuilder result = new StringBuilder(2 * value.Length);
foreach (char c in value) {
if (count != 0 && c != current) {
result.Append(count);
result.Append(current);
count = 0;
}
current = c;
count += 1;
}
result.Append(count);
result.Append(current);
return result.ToString();
}
Please, fiddle yourself

Well, I ended with the following code sample:
public static void Main()
{
string str = "AAAAABBCCCDDDDAABBBBAABB";
int count = 1;
char[] charVal = str.ToCharArray();
List<string> charCnt = new List<string>();
charCnt.Add("");
string concat = "";
//Getting each letters using foreach loop
foreach (var ch in charVal)
{
var lastItem = charCnt.LastOrDefault();
if (lastItem.EndsWith((ch.ToString()))) //If letter exists, then count and replace the last value
{
count++;
charCnt[charCnt.Count - 1] = count.ToString() + ch.ToString();
}
else
{
charCnt.Add(ch.ToString()); //If no matching letter exists, then add it to the list initially
count = 1;
}
}
foreach (var item in charCnt)
{
concat += item; //Concatenate items from the list
}
Console.WriteLine(concat.Trim());
}
Here's a woking sample: Get Occurrences of Letters in A String

Related

Is there a way to remove a character from a string in this program?

I am tasked with reading the first character in the sentence and count how many times that character occurs. I must then move on to the next character that has not been counted yet and
static void Main(string[] args)
{
char[] array = fullword.ToCharArray();
foreach (char ch in array)
{
Console.WriteLine(GetHowManyTimeOccurenceCharInString(fullword, ch));
}
}
public static int GetHowManyTimeOccurenceCharInString(string text, char c)
{
int count = 0;
foreach (char ch in text)
{
if (ch.Equals(c))
{
count++;
}
}
return count;
}
}
Ok here it is. Just a little program to show you how to do that. First convert your string into a Char arrar and add that to a List. Then you can remove chars from the list using the RemoveAt(n) method. Finally you change your list into a string again and voila there are "JackandJill" again.
using System;
using System.Collections.Generic;
using System.Text;
namespace RemoveChars
{
internal class Program
{
static void Main(string[] args)
{
string name = "Jack and Jill";
var list = new List<char>();
list.AddRange(name.ToCharArray());
list.RemoveAt(4);
list.RemoveAt(7);
var sb = new StringBuilder();
list.ForEach(x => sb.Append(x));
Console.WriteLine(sb.ToString());
Console.ReadKey();
}
}
}
I believe you are trying to get the number of character occurrences in a string.
This will give you a dictionary of character and count.
public Dictionary<char, int> GetNoOfOccurenceCharInString(string stringToCheck)
{
//Track the character and count in a Dictionary.
Dictionary<char, int> map = new Dictionary<char, int>();
//For String "Jack and Jill" it will store something like this in the memory
// j =2, a = 2, c = 1, k = 1, " " = 2, n = 1, d = 1, i = 1, l = 2
//Shift to Lower case and Loop through each character
foreach (var c in stringToCheck.ToLower())
{
if (c == ' ') //If the current char is a space do not count;
{
continue;
}
//Check if map already has the char, if yes use the count stored in the memory, else initialize to 0
var count = map.ContainsKey(c) ? map[c] : 0;
map[c] = count + 1; //Increment count by 1
}
return map;
}
To test this:
string name1 = "Jack";
string matches = "matches";
string name2 = "Jill";
string fullword = name1 + matches + name2;
//Call our method
var result = GetNoOfOccurenceCharInString(fullword);
//loop through each key in the Dictionary
foreach (var key in result.Keys)
{
//Print out the Key and the Count
Console.WriteLine($"{key}: {result[key]}");
}
The best way to do what you need is to create a counting HashMap. I will put this example made in java.
public static void main(String[] args) {
String name1 = "jack";
String matches = "matches";
String name2 = "jill";
String fullWord = name1 + matches + name2;
//Map to get the number of repeated characters
HashMap<Character, Integer> counts = new HashMap<>();
//New string without repeated characters
StringBuilder noRepeatingCharacter = new StringBuilder();
// Text string with the number of repeated characters
StringBuilder literalCounts = new StringBuilder();
for (int i = 0; i < fullWord.length(); i++) {
//We get the character to establish if it is repeated or not.
char charAr = fullWord.charAt(i);
//We verify if in our map the character exists
if (counts.containsKey(charAr)) {
// Update counts
counts.replace(charAr, counts.get(charAr) + 1);
} else {
// we add to our new string of characters only the non-repeated ones
noRepeatingCharacter.append(charAr);
// If the character does not exist in our map, we add it
counts.put(charAr, 1);
}
}
// So that we can print the count in order, we assign to our variable literalCounts
for (int i = 0; i < noRepeatingCharacter.length(); i++) {
char charAr = noRepeatingCharacter.charAt(i);
literalCounts.append(counts.get(charAr));
}
// Print counts
System.out.println("Counts: " + literalCounts);
}
Output
Output

How do I get the exact position of regex matches?

For example assume I have a text string
What is the value of pn in 1 ;/
This is a test 12./ lop
I want to get the exact line position of the regex matches for the regex pattern \d\s?[.,;:]\s?/. How can I do that
I've tried
string text = #"What is the value of pn in 1 ;/
This is a test 12./ lop";
string pattern = #"\d\s?[.,;:]\s?/";
foreach (Match m in Regex.Matches(text, pattern))
{
var info=LineFromPos(text,m.Index);
Console.WriteLine(info+","+m.Index);
}
Console.Read();
}
public static int LineFromPos(string S, int Pos)
{
int Res = 1;
for (int i = 0; i <= Pos - 1; i++)
if (S[i] == '\n') Res++;
return Res;
}
But the code outputs
1,27
2,49
Where it should be
1,27
2,16
How do I fix this?
You can try something like this:
string text = #"What is the value of pn in 1 ;/
This is a test 12./ lop";
string pattern = #"\d\s?[.,;:]\s?/";
var lines = Regex.Split(text, "\r\n|\r|\n").Where(s => s != String.Empty)
.ToList();
for (int i = 0; i < lines.Count; i++)
{
foreach (Match m in Regex.Matches(lines[i], pattern))
{
Console.WriteLine(string.Format("{0},{1}", i + 1, m.Index));
}
}
You're currently treating m.Index as if it's the position in the line, but it's actually the position in the string it sounds like you may want to write a method to convert from a string index into a position (both line and index within line) - assuming you want to keep the matches within a single string.
For example (using ValueTuple and C# 7 syntax - you could create your own line/column type otherwise):
static (int line, int column) FindPosition(string text, int index)
{
int line = 0;
int current = 0;
while (true)
{
int next = text.IndexOf('\n', current);
if (next > index || next == -1)
{
return (line, index - current);
}
current = next + 1;
line++;
}
}
We could be more efficient than that by remembering the position of the previous match, but it's simpler to keep it as just accepting the string and index.
Here's a complete example of that in your code:
using System;
using System.Text.RegularExpressions;
static class Int32Extensions
{
// This doesn't do what you might expect it to!
public static void Increment(this int x)
{
x = x + 1;
}
}
class Test
{
static void Main()
{
string text = #"What is the value of pn in 1 ;/
This is a test 12./ lop";
string pattern = #"\d\s?[.,;:]\s?/";
foreach (Match m in Regex.Matches(text, pattern))
{
var position = FindPosition(text, m.Index);
Console.WriteLine($"{position.line}, {position.column}");
}
}
static (int line, int column) FindPosition(string text, int index)
{
int line = 0;
int current = 0;
while (true)
{
int next = text.IndexOf('\n', current);
if (next > index || next == -1)
{
return (line, index - current);
}
current = next + 1;
line++;
}
}
}
That prints output of:
0, 27
1, 16
That's using 0-based line and column numbers - obviously you can add 1 when you display the values if you want to.

How to reverse an array of strings without changing the position of special characters in C#

I'm working on reversing a sentence. I'm able to do it. But I'm not sure, how to reverse the word without changing the special characters positions. I'm using regex but as soon as it finds the special characters it's stopping the reversal of the word.
Following is the code:
Console.WriteLine("Enter:");
string w = Console.ReadLine();
string rw = String.Empty;
String[] arr = w.Split(' ');
var regexItem = new Regex("^[a-zA-Z0-9]*$");
StringBuilder appendString = new StringBuilder();
for (int i = 0; i < arr.Length; i++)
{
char[] chararray = arr[i].ToCharArray();
for (int j = chararray.Length - 1; j >= 0; j--)
{
if (regexItem.IsMatch(rw))
{
rw = appendString.Append(chararray[j]).ToString();
}
}
sb.Append(' ');
}
Console.WriteLine(rw);
Console.ReadLine();
Example : Input
Marshall! Hello.
Expected output
llahsram! olleh.
A basic solution with regex and LINQ. Try it online.
public static void Main()
{
Console.WriteLine("Marshall! Hello.");
Console.WriteLine(Reverse("Marshall! Hello."));
}
public static string Reverse(string source)
{
// we split by groups to keep delimiters
var parts = Regex.Split(source, #"([^a-zA-Z0-9])");
// if we got a group of valid characters
var results = parts.Select(x => x.All(char.IsLetterOrDigit)
// we reverse it
? new string(x.Reverse().ToArray())
// or we keep the delimiters as it
: x);
// then we concat all of them
return string.Concat(results);
}
The same solution without LINQ. Try it online.
public static void Main()
{
Console.WriteLine("Marshall! Hello.");
Console.WriteLine(Reverse("Marshall! Hello."));
}
public static bool IsLettersOrDigits(string s)
{
foreach (var c in s)
{
if (!char.IsLetterOrDigit(c))
{
return false;
}
}
return true;
}
public static string Reverse(char[] s)
{
Array.Reverse(s);
return new string(s);
}
public static string Reverse(string source)
{
var parts = Regex.Split(source, #"([^a-zA-Z0-9])");
var results = new List<string>();
foreach(var x in parts)
{
results.Add(IsLettersOrDigits(x)
? Reverse(x.ToCharArray())
: x);
}
return string.Concat(results);
}
This is a solution without LINQ. I wasn't sure about what are considered special characters.
string sentence = "Marshall! Hello.";
List<string> words = sentence.Split(' ').ToList();
List<string> reversedWords = new List<string>();
foreach (string word in words)
{
char[] arr = new char[word.Length];
for( int i=0; i<word.Length; i++)
{
if(!Char.IsLetterOrDigit((word[i])))
{
for ( int x=0; x< i; x++)
{
arr[x] = arr[x + 1];
}
arr[i] = word[i];
}
else
{
arr[word.Length - 1 - i] = word[i];
}
}
reversedWords.Add(new string(arr));
}
string reversedSentence = string.Join(" ", reversedWords);
Console.WriteLine(reversedSentence);
And this is the output:
Updated Output = llahsraM! olleH.
Here is a non-regex version that does what you want:
var sentence = "Hello, john!";
var parts = sentence.Split(' ');
var reversed = new StringBuilder();
var charPositions = sentence.Select((c, idx) => new { Char = c, Index = idx })
.Where(_ => !char.IsLetterOrDigit(_.Char));
for (int i = 0; i < parts.Length; i++)
{
var chars = parts[i].ToCharArray();
for (int j = chars.Length - 1; j >= 0; j--)
{
if (char.IsLetterOrDigit(chars[j]))
{
reversed.Append(chars[j]);
}
}
}
foreach (var ch in charPositions)
{
reversed.Insert(ch.Index, ch.Char);
}
// olleH, nhoj!
Console.WriteLine(reversed.ToString());
Basically the trick is to remember the position of special (i.e. non letter or digit) characters and insert them at the end to those positions.
This solution is without LINQ and Regex. It may not be an efficient answer but working properly for small string values.
// This will reverse the string and special characters will just stay there.
public string ReverseString(string rString)
{
StringBuilder ss = new StringBuilder(rString);
int y = 0;
// The idea is to swap values. Like swapping first value with last one. It will keep swapping unless it reaches at the middle of the string where no swapping will be needed.
// This first loop is to detect first values.
for(int i=rString.Length-1;i>=0;i--)
{
// This condition is to check if the values is String or not. If it is not string then it is considered as special character which will just stay there at same old position.
if(Char.IsLetter(Convert.ToChar(rString.Substring(i,1))))
{
// This is second loop which is starting from end to swap values from end with first.
for (int k = y; k < rString.Length; k++)
{
// Again checking last values if values are string or not.
if (Char.IsLetter(Convert.ToChar(rString.Substring(k, 1))))
{
// This is swapping. So st1 is First value in that string
// st2 is the last item in that string
char st1 = Convert.ToChar(rString.Substring(k, 1));
char st2 = Convert.ToChar(rString.Substring(i, 1));
//This is swapping. So last item will go to first position and first item will go to last position, To make sure string is reversed.
// Remember when the string value is Special Character, swapping will move forward without swapping.
ss[rString.IndexOf(rString.Substring(i, 1))] = st1;
ss[rString.IndexOf(rString.Substring(k, 1))] = st2;
y++;
// When the swapping is done for first 2 items. The loop will stop to change the values.
break;
}
else
{
// This is just increment if value was Special character.
y++;
}
}
}
}
return ss.ToString();
}
Thanks!

Find and count latter pair from a string by alphabetical order

I am working on a small project which is in C# where I want to find and count the latter pairs which comes in alphabetical order by ignoring spaces and special characters.
e.g.
This is a absolutely easy.
Here my output should be
hi 1
ab 1
I refereed This post but not getting exact idea for pair latter count.
First I remove the spaces and special characters as you specified by simply going though the string and checking whether the current character is a letter:
private static string GetLetters(string s)
{
string newString = "";
foreach (var item in s)
{
if (char.IsLetter(item))
{
newString += item;
}
}
return newString;
}
Than I wrote a method which checks if the next letter is in alphabetical order using simple logic. I lower the character's case and check if the current character's ASCII code + 1 is equal to the next one's. If it is, of course they are the same:
private static string[] GetLetterPairsInAlphabeticalOrder(string s)
{
List<string> pairs = new List<string>();
for (int i = 0; i < s.Length - 1; i++)
{
if (char.ToLower(s[i]) + 1 == char.ToLower(s[i + 1]))
{
pairs.Add(s[i].ToString() + s[i+1].ToString());
}
}
return pairs.ToArray();
}
Here is how the main method will look like:
static void Main()
{
string s = "This is a absolutely easy.";
s = GetLetters(s);
string[] pairOfLetters = GetLetterPairsInAlphabeticalOrder(s);
foreach (var item in arr)
{
Console.WriteLine(item);
}
}
First, I would normalize the string to reduce confusion from special characters like this:
string str = "This is a absolutely easy.";
Regex rgx = new Regex("[^a-zA-Z]");
str = rgx.Replace(str, "");
str = str.ToLower();
Then, I would loop over all of the characters in the string and see if their neighbor is the next letter in the alphabet.
Dictionary<string, int> counts = new Dictionary<string, int>();
for (int i = 0; i < str.Length - 1; i++)
{
if (str[i+1] == (char)(str[i]+1))
{
string index = "" + str[i] + str[i+1];
if (!counts.ContainsKey(index))
counts.Add(index, 0);
counts[index]++;
}
}
Printing the counts from there is pretty straightforward.
foreach (string s in counts.Keys)
{
Console.WriteLine(s + " " + counts[s]);
}

Counting number of words in C#

I'm trying to count the number of words from a rich textbox in C# the code that I have below only works if it is a single line. How do I do this without relying on regex or any other special functions.
string whole_text = richTextBox1.Text;
string trimmed_text = whole_text.Trim();
string[] split_text = trimmed_text.Split(' ');
int space_count = 0;
string new_text = "";
foreach(string av in split_text)
{
if (av == "")
{
space_count++;
}
else
{
new_text = new_text + av + ",";
}
}
new_text = new_text.TrimEnd(',');
split_text = new_text.Split(',');
MessageBox.Show(split_text.Length.ToString ());
char[] delimiters = new char[] {' ', '\r', '\n' };
whole_text.Split(delimiters,StringSplitOptions.RemoveEmptyEntries).Length;
Since you are only interested in word count, and you don't care about individual words, String.Split could be avoided. String.Split is handy, but it unnecessarily generates a (potentially) large number of String objects, which in turn creates an unnecessary burden on the garbage collector. For each word in your text, a new String object needs to be instantiated, and then soon collected since you are not using it.
For a homework assignment, this may not matter, but if your text box contents change often and you do this calculation inside an event handler, it may be wiser to simply iterate through characters manually. If you really want to use String.Split, then go for a simpler version like Yonix recommended.
Otherwise, use an algorithm similar to this:
int wordCount = 0, index = 0;
// skip whitespace until first word
while (index < text.Length && char.IsWhiteSpace(text[index]))
index++;
while (index < text.Length)
{
// check if current char is part of a word
while (index < text.Length && !char.IsWhiteSpace(text[index]))
index++;
wordCount++;
// skip whitespace until next word
while (index < text.Length && char.IsWhiteSpace(text[index]))
index++;
}
This code should work better with cases where you have multiple spaces between each word, you can test the code online.
There are some better ways to do this, but in keeping with what you've got, try the following:
string whole_text = richTextBox1.Text;
string trimmed_text = whole_text.Trim();
// new line split here
string[] lines = trimmed_text.Split(Environment.NewLine.ToCharArray());
// don't need this here now...
//string[] split_text = trimmed_text.Split(' ');
int space_count = 0;
string new_text = "";
Now make two foreach loops. One for each line and one for counting words within the lines.
foreach (string line in lines)
{
// Modify the inner foreach to do the split on ' ' here
// instead of split_text
foreach (string av in line.Split(' '))
{
if (av == "")
{
space_count++;
}
else
{
new_text = new_text + av + ",";
}
}
}
new_text = new_text.TrimEnd(',');
// use lines here instead of split_text
lines = new_text.Split(',');
MessageBox.Show(lines.Length.ToString());
}
This was a phone screening interview question that I just took (by a large company located in CA who sells all kinds of devices that starts with a letter "i"), and I think I franked... after I got offline, I wrote this. I wish I were able to do it during interview..
static void Main(string[] args)
{
Debug.Assert(CountWords("Hello world") == 2);
Debug.Assert(CountWords(" Hello world") == 2);
Debug.Assert(CountWords("Hello world ") == 2);
Debug.Assert(CountWords("Hello world") == 2);
}
public static int CountWords(string test)
{
int count = 0;
bool wasInWord = false;
bool inWord = false;
for (int i = 0; i < test.Length; i++)
{
if (inWord)
{
wasInWord = true;
}
if (Char.IsWhiteSpace(test[i]))
{
if (wasInWord)
{
count++;
wasInWord = false;
}
inWord = false;
}
else
{
inWord = true;
}
}
// Check to see if we got out with seeing a word
if (wasInWord)
{
count++;
}
return count;
}
Have a look at the Lines property mentioned in #Jay Riggs comment, along with this overload of String.Split to make the code much simpler. Then the simplest approach would be to loop over each line in the Lines property, call String.Split on it, and add the length of the array it returns to a running count.
EDIT: Also, is there any reason you're using a RichTextBox instead of a TextBox with Multiline set to True?
I use an extension method for grabbing word count in a string. Do note, however, that double spaces will mess the count up.
public static int CountWords(this string line)
{
var wordCount = 0;
for (var i = 0; i < line.Length; i++)
if (line[i] == ' ' || i == line.Length - 1)
wordCount++;
return wordCount;
}
}
Your approach is on the right path. I would do something like, passing the text property of richTextBox1 into the method. This however won't be accurate if your rich textbox is formatting HTML, so you'll need to strip out any HTML tags prior to running the word count:
public static int CountWords(string s)
{
int c = 0;
for (int i = 1; i < s.Length; i++)
{
if (char.IsWhiteSpace(s[i - 1]) == true)
{
if (char.IsLetterOrDigit(s[i]) == true ||
char.IsPunctuation(s[i]))
{
c++;
}
}
}
if (s.Length > 2)
{
c++;
}
return c;
}
We used an adapted form of Yoshi's answer, where we fixed the bug where it would not count the last word in a string if there was no white-space after it:
public static int CountWords(string test)
{
int count = 0;
bool inWord = false;
foreach (char t in test)
{
if (char.IsWhiteSpace(t))
{
inWord = false;
}
else
{
if (!inWord) count++;
inWord = true;
}
}
return count;
}
using System.Collections;
using System;
class Program{
public static void Main(string[] args){
//Enter the value of n
int n = Convert.ToInt32(Console.ReadLine());
string[] s = new string[n];
ArrayList arr = new ArrayList();
//enter the elements
for(int i=0;i<n;i++){
s[i] = Console.ReadLine();
}
string str = "";
//Filter out duplicate values and store in arr
foreach(string i in s){
if(str.Contains(i)){
}else{
arr.Add(i);
}
str += i;
}
//Count the string with arr and s variables
foreach(string i in arr){
int count = 0;
foreach(string j in s){
if(i.Equals(j)){
count++;
}
}
Console.WriteLine(i+" - "+count);
}
}
}
int wordCount = 0;
bool previousLetterWasWhiteSpace = false;
foreach (char letter in keyword)
{
if (char.IsWhiteSpace(letter))
{
previousLetterWasWhiteSpace = true;
}
else
{
if (previousLetterWasWhiteSpace)
{
previousLetterWasWhiteSpace = false;
wordCount++;
}
}
}
public static int WordCount(string str)
{
int num=0;
bool wasInaWord=true;;
if (string.IsNullOrEmpty(str))
{
return num;
}
for (int i=0;i< str.Length;i++)
{
if (i!=0)
{
if (str[i]==' ' && str[i-1]!=' ')
{
num++;
wasInaWord=false;
}
}
if (str[i]!=' ')
{
wasInaWord=true;
}
}
if (wasInaWord)
{
num++;
}
return num;
}
class Program
{
static void Main(string[] args)
{
string str;
int i, wrd, l;
StringBuilder sb = new StringBuilder();
Console.Write("\n\nCount the total number of words in a string
:\n");
Console.Write("---------------------------------------------------
---\n");
Console.Write("Input the string : ");
str = Console.ReadLine();
l = 0;
wrd = 1;
foreach (var a in str)
{
sb.Append(a);
if (str[l] == ' ' || str[l] == '\n' || str[l] == '\t')
{
wrd++;
}
l++;
}
Console.WriteLine(sb.Replace(' ', '\n'));
Console.Write("Total number of words in the string is : {0}\n",
wrd);
Console.ReadLine();
}
This should work
input.Split(' ').ToList().Count;
This can show you the number of words in a line
string line = Console.ReadLine();
string[] word = line.Split(' ');
Console.WriteLine("Words " + word.Length);
You can also do it in this way!! Add this method to your extension methods.
public static int WordsCount(this string str)
{
return Regex.Matches(str, #"((\w+(\s?)))").Count;
}
And call it like this.
string someString = "Let me show how I do it!";
int wc = someString.WordsCount();

Categories