Mustafa
Mustafa

Reputation: 129

iterate through string and count occurrences

This is the question:

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]);
        }

Upvotes: 0

Views: 3655

Answers (4)

Zenilogix
Zenilogix

Reputation: 1393

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:

  1. 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).
  2. 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.
  3. 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.

Upvotes: 0

CinnamonBun
CinnamonBun

Reputation: 1150

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);
}

Upvotes: 2

fex
fex

Reputation: 3558

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

Upvotes: 1

Fawar
Fawar

Reputation: 735

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

Upvotes: 2

Related Questions