This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have a string a = "aabbbffdshhh". I want to write a program which will give me output of "a2b3f2d1s1h3". I want to return each letter in the alphabet present and it's count.
The code I am currently using is:
int cnta;int cntb; int cntf; int cnth;
for (int i=0;i<a.lenghth;i++)
{
if(a[i]=='a')
{
cnta++;
}
if(a[i]=='b')
{
cntb++;
}
if(a[i]=='h')
{
cnth++;
}
}
It is giving me the output but this logic not good. What other algorithms or approaches could I use?
This should give you all of the data that you need for your results.
You should be able to append them into a string (using a StringBuilder) if you need the results in that format.
var results = s.GroupBy(c => c)
.Select(group => new
{
Letter = group.Key,
Count = group.Count()
});
One idea is to have a List<Tuple<char,int>> where you pre-populate with each char and 0 for it.
Increment the value of each character when encountered.
for (int i=0;i<a.lenghth;i++)
{
myList.Single(t => t.Item1 == a[i]).Item2++;
}
in general terms:
sort characters to obtain a sorted list with 1 instance of each char
create a list of counters the same size as the sorted list (each counter starts at 0)
loop over each char in the string incrementing the corosponding counters
loop over the sorted list constructing the result from the sorted list and counters.
var input = "aabbbffdshhh";
var characters = input.ToArray();
StringBuilder sb = new StringBuilder();
characters.ToList().ForEach(c=>{if(!sb.ToString().Contains(c)){sb.Append(c); sb.Append(characters.ToList().Count(cc=>cc == c));}});
//sb.ToString().Dump(); //output is a2b3f2d1s1h3
Done in LinqPad
Use a dictionary of type Dictionary. On the first occurrence add to the dictionary, on every subsequent increment.
This way you can use whatever characters you want (and control how to treat case) rather than just handling the 26
Assuming you're doing a slight variation of Run-length Encoding, this will encode your string. My comment went unanswered so I'm posing this as a guess. I'll leave the decoding as an exercise to you (or just check out rosettacode to see the implementation).
var a = "aabbbffdshhh";
var rle = new StringBuilder();
var last = a[0];
var count = 1;
for (int i = 1; i < a.Length; i++)
{
if (a[i] != last)
{
rle.AppendFormat("{0}{1}", last, count);
last = a[i];
count = 0;
}
count++;
}
rle.AppendFormat("{0}{1}", last, count);
Assert.AreEqual("a2b3f2d1s1h3", rle.ToString());
Can be done with 1 line of super readable code (sarcasm) :-) I have added an orderby even though this wasn't requested, you can remove if needed.
string a = "aaaadjkhsdfkjsdjkfhsdkjff";
var res = a.GroupBy(c => c).OrderBy(g => g.Key).Aggregate("", (p, g) => p += g.Key + g.Count().ToString());
or if you are one of those who think string concatenation is too inefficient
var res2 = a.GroupBy(c => c).OrderBy(g => g.Key).Aggregate(new StringBuilder(), (p, g) => p.Append(g.Key + g.Count().ToString())).ToString();;
in C# you could do:
Dictionary<char, int> d = new Dictionary<char, int>();
foreach(char c in a){
if(d.ContainsKey(c)){
d[c] = d[c] + 1;
} else {
d[c] = 1;
}
}
StringBuilder sb = new StringBuilder();
foreach(KeyValuePair p in d){
sb += p.Key.ToString() + p.Value.Tostring();
}
return sb.ToString();
Try this:
string a = "aaabbbasdlfjasldfkjalsdkfjaewoasdfj";
//store character counts in a dictionary
Dictionary<char, int> charCounts = new Dictionary<char, int>();
//iterate through string and place counts in dictionary
for (int i = 0; i < a.Length; i++)
{
if (!charCounts.Keys.Contains(a[i]))
{
charCounts[a[i]] = 1;
}
else
{
charCounts[a[i]] += 1;
}
}
//output sorted list
foreach (char letter in charCounts.Keys.OrderBy(x => x))
{
Console.Write(string.Format("{0}{1}", letter, charCounts[letter]));
}
this code should work in cpp
int* count = new int[26];
for (int i = 0; i < a.length; i++)
count[a[i] - 'a']++;
in c# you will need to play around a little so you well look at a char as a number.
Related
I have a function findChar() that loops through a string to find occurrences of characters in a string Ex: "Cincinnati" (2 Cs, 2 i's, etc) but once it finds another 'C' or 'i' it will return the values again
public static int findChar(string name, char c)
{
int count = 0;
for (int i = 0; i < name.Length; i++)
{
if (name[i] == c || name[i] == Char.ToUpper(c) || name[i] == Char.ToLower(c))
{
count++;
}
}
return count;
}
static void Main(string[] args)
{
string name = "Cincinnati";
char c = ' ' ;
int count = 0;
for (int i = 0; i < name.Length; i++)
{
c = name[i];
count = findChar(name, c);
Console.WriteLine(count);
}
}
My Output looks like this:
2
3
3
2
3
3
3
1
1
3
And I need it to be like:
2
3
3
1
1
Option 1: keep track of the letters you already processed, and ignore it if you already did
Option 2: use System.Linq's GroupBy to get the count
public static void Main()
{
var name = "Cincinatti";
var letters = name.ToLower().GroupBy(letter => letter);
foreach (var group in letters) {
Console.WriteLine(group.Count());
}
}
There are many ways to solve a problem like this. First let's discuss a problem it looks like you've already run into, capitalization. Lower case and upper case versions of the same letter are classified as different characters. The easiest way to combat this is to either convert the string to lowercase or uppercase so each duplicate letter can also be classified as a duplicate character. You can do this either by using the String.ToLower() method or the String.ToUpper() method depending on which one you want to use.
The way to solve this that is the closest to what you have is to just create a list, add letters to it as you process them, then use the list to check what letters you've processed already. It would look something like this:
static void Main(string[] args)
{
string name = "Cincinnati";
char c = ' ' ;
int count = 0;
var countedLetters = new List<string>();
for (int i = 0; i < name.Length; i++)
{
c = name[i];
char cLower = char.ToLower(c);
if(countedLetters.Contains(cLower))
{
continue;
}
countedLetters.Add(cLower);
count = findChar(name, c);
Console.WriteLine(count);
}
}
Although, you can usually use System.Linq's Enumerable extension methods to do things like this pretty easily.
Not deviating too much from what you have, another solution using System.Linq would be to just get the distinct characters and loop through that instead of the entire string. When doing this, we need to convert the entire string to either upper or lower case in order for linq to return the expected result. This would like something like this:
static void Main(string[] args)
{
string name = "Cincinnati";
string nameLower = name.ToLower();
int count = 0;
foreach(char c in nameLower.Distinct())
{
count = findChar(name, c);
Console.WriteLine(count);
}
}
Then finally, you can simplify this a ton by leaning heavily into the linq route. GroupBy is very useful for this because it's entire purpose is to group duplicates together. There are many ways to implement this and two have already be provided, so I will just provide a third.
public static void Main()
{
string name = "Cincinatti";
int[] counts = name.ToLower()
.GroupBy(letter => letter)
.Select(group => group.Count())
.ToArray();
Console.WriteLine(string.Join("\n", counts));
}
you can do group by list, sort optional (i left it commented out) and then select count
var word="Cincinnati";
var groups = word.ToLower().GroupBy(n => {return n;})
.Select(n => new
{
CharachterName = n.Key,
CharachterCount = n.Count()
});
// .OrderBy(n => n.CharachterName);
Console.WriteLine(JsonConvert.SerializeObject(groups.Select(i=>i.CharachterCount)));
My question is:
How do you check if a given string is the anagram of a palindrome?
I found some solutions in Python on the internet, but I'm not sure how can I check this yet. I was thinking about converting the strig to a char [], and then get the HashCode for every character, but I'm stuck.
If you're not interested in the palindrome or anagram being a real word then I think you can reframe the problem as check if a given string has no more than one character that appears an uneven number of times. This is on the basis that only the middle character can possibly occur an odd number of times. As long as that is satisfied then you can form a palindrome from the string.
To do that you can use Linq. Something like this perhaps:
private static bool IsPalindromeAnagram(string test)
{
var charCount = test.GroupBy(c => c, (c, i) => new
{
character = c,
count = i.Count()
});
return charCount.Count(c => c.count % 2 == 1) <= 1;
}
Saved char in a dictionary as key, then check if more than one key is odd. this way also have all unique char ready to make anagram.
var length = s.Length;
if (length == 0) return false;
var dic = new Dictionary<char, int>();
for (var i = 0; i < length; i++)
{
if (dic.ContainsKey(s[i]))
{
dic[s[i]]++;
continue;
}
dic.Add(s[i], 1);
}
int odd = 0;
foreach (var pv in dic)
{
if (odd > 1) return false;
if (pv.Value % 2 == 0)
{
continue;
}
odd++;
}
This question already has answers here:
Splitting a string into chunks of a certain size
(39 answers)
Split string after certain character count
(4 answers)
Closed 8 years ago.
I have a text file with various 16 char strings both appended to one another and on separate lines. I've done this
FileInfo f = new FileInfo("d:\\test.txt");
string FilePath = ("d:\\test.txt");
string FileText = new System.IO.StreamReader(FilePath).ReadToEnd().Replace("\r\n", "");
CharCount = FileText.Length;
To remove all of the new lines and create one massively appended string. I need now to split this massive string into an array. I need to split it up on the consecutive 16th char until the end. Can anyone guide me in the right direction? I've taken a look at various methods in String such as Split and in StreamReader but am confused as to what the best way to go about it would be. I'm sure it's simple but I can't figure it out.
Thank you.
Adapting the answer from here:
You could try something like so:
string longstr = "thisisaverylongstringveryveryveryveryverythisisaverylongstringveryveryveryveryvery";
IEnumerable<string> splitString = Regex.Split(longstr, "(.{16})").Where(s => s != String.Empty);
foreach (string str in splitString)
{
System.Console.WriteLine(str);
}
Yields:
thisisaverylongs
tringveryveryver
yveryverythisisa
verylongstringve
ryveryveryveryve
ry
One possible solution could look like this (extracted as extension method and made dynamic, in case different token size is needed and no hard-coded dependencies):
public static class ProjectExtensions
{
public static String[] Chunkify(this String input, int chunkSize = 16)
{
// result
var output = new List<String>();
// temp helper
var chunk = String.Empty;
long counter = 0;
// tokenize to 16 chars
input.ToCharArray().ToList().ForEach(ch =>
{
counter++;
chunk += ch;
if ((counter % chunkSize) == 0)
{
output.Add(chunk);
chunk = String.Empty;
}
});
// add the rest
output.Add(chunk);
return output.ToArray();
}
}
The standard usage (16 chars) looks like this:
// 3 inputs x 16 characters and 1 x 10 characters
var input = #"1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890";
foreach (var chunk in input.Chunkify())
{
Console.WriteLine(chunk);
}
The output is:
1234567890ABCDEF
1234567890ABCDEF
1234567890ABCDEF
1234567890
Usage with different token size:
foreach (var chunk in input.Chunkify(13))
{
Console.WriteLine(chunk);
}
and the corresponding output:
1234567890ABC
DEF1234567890
ABCDEF1234567
890ABCDEF1234
567890
It is not a fancy solution (and could propably be optimised for speed), but it works and it is easy to understand and implement.
Create a list to hold your tokens. Then get subsequent substrings of length 16 and add them to the list.
List<string> tokens = new List<string>();
for(int i=0; i+16<=FileText.Length; i+=16) {
tokens.Add(FileText.Substring(i,16));
}
As mentioned in the comments, this ignores the last token if it has less than 16 characters. If you want it anyway you can write:
List<string> tokens = new List<string>();
for(int i=0; i<FileText.Length; i+=16) {
int len = Math.Min(16, FileText.Length-i));
tokens.Add(FileText.Substring(i,len);
}
Please try this method. I haven't tried it , but used it once.
int CharCount = FileText.Length;
int arrayhold = (CharCount/16)+2;
int count=0;
string[] array = new string[arrayhold];
for(int i=0; i<FileText.Length; i+=16)
{
int currentleft = FileText.Length-(16*count);
if(currentleft>16)
{
array[count]=FileText.Substring(i,16);
}
if(currentleft<16)
{
array[count]=FileText.Substring(i,currentleft);
}
count++;
}
This is the new code and provide a TRUE leftovers handling. Tested in ideone
Hope it works
Try this one:
var testArray = "sdfsdfjshdfalkjsdfhalsdkfjhalsdkfjhasldkjfhasldkfjhasdflkjhasdlfkjhasdlfkjhasdlfkjhasldfkjhalsjfdkhklahjsf";
var i = 0;
var query = from s in testArray
let num = i++
group s by num / 16 into g
select new {Value = new string(g.ToArray())};
var result = query.Select(x => x.Value).ToList();
result is List containing all the 16 char strings.
I'm trying to have a suggestion feature for the search function in my program eg I type janw doe in the search section and it will output NO MATCH - did you mean jane doe? I'm not sure what the problem is, maybe something to do with char/string comparison..I've tried comparing both variables as type char eg char temp -->temp.Contains ...etc but an error appears (char does not contain a definition for Contains). Would love any help on this! 8)
if (found == false)
{
Console.WriteLine("\n\nMATCH NOT FOUND");
int charMatch = 0, charCount = 0;
string[] checkArray = new string[26];
//construction site /////////////////////////////////////////////////////////////////////////////////////////////////////////////
for (int controlLoop = 0; controlLoop < contPeople.Length; controlLoop++)
{
foreach (char i in userContChange)
{
charCount = charCount + 1;
}
for (int i = 0; i < userContChange.Length; )
{
string temp = contPeople[controlLoop].name;
string check=Convert.ToString(userContChange[i]);
if (temp.Contains(check))
{
charMatch = charMatch + 1;
}
}
int half = charCount / 2;
if (charMatch >= half)
{
checkArray[controlLoop] = contPeople[controlLoop].name;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
Console.WriteLine("Did you mean: ");
for (int a = 0; a < checkArray.Length; a++)
{
Console.WriteLine(checkArray[a]);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
A string is made up of many characters. A character is a primitive, likewise, it doesn't "contain" any other items. A string is basically an array of characters.
For comparing string and characters:
char a = 'A';
String alan = "Alan";
Debug.Assert(alan[0] == a);
Or if you have a single digit string.. I suppose
char a = 'A';
String alan = "A";
Debug.Assert(alan == a.ToString());
All of these asserts are true
But, the main reason I wanted to comment on your question, is to suggest an alternative approach for suggesting "Did you mean?". There's an algorithm called Levenshtein Distance which calculates the "number of single character edits" required to convert one string to another. It can be used as a measure of how close two strings are. You may want to look into how this algorithm works because it could help you.
Here's an applet that I found which demonstrates: Approximate String Matching with k-differences
Also the wikipedia link Levenshtein distance
Char type cannot have .Contains() because is only 1 char value type.
In your case (if i understand), maybe you need to use .Equals() or the == operator.
Note: for compare String correctly, use .Equals(),
the == operator does not work good in this case because String is reference type.
Hope this help!
char type dosen't have the Contains() method, but you can use iit like this: 'a'.ToString().Contains(...)
if do not consider the performance, another simple way:
var input = "janw doe";
var people = new string[] { "abc", "123", "jane", "jane doe" };
var found = Array.BinarySearch<string>(people, input);//or use FirstOrDefault(), FindIndex, search engine...
if (found < 0)//not found
{
var i = input.ToArray();
var target = "";
//most similar
//target = people.OrderByDescending(p => p.ToArray().Intersect(i).Count()).FirstOrDefault();
//as you code:
foreach (var p in people)
{
var count = p.ToArray().Intersect(i).Count();
if (count > input.Length / 2)
{
target = p;
break;
}
}
if (!string.IsNullOrWhiteSpace(target))
{
Console.WriteLine(target);
}
}
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);
}