user1797574
user1797574

Reputation:

Counting letter frequencies

I'm reading in a text file using StreamReader to the program. I need to record the frequency of each letter in the string into an array (where index 0 would be A, and so on). What's the simplest approach for this?

Edit: I had this originally, until I realized it was completely wrong.

int counter = 0;
int[] freq = new int[26]; // create frequency array

// counts frequency
while (counter < inValue.Length)
{
      int A = 65; // ASCII value for "A"
      char x = char.Parse(inValue.Substring(counter, 1)); // get individual characters from string
       int s = (int)x; // cast character to integer value

       if (s == A + counter)
             freq[counter]++;

             counter++;
 }

Where inValue is the text file StreamReader reads into the program.

Upvotes: 2

Views: 6697

Answers (4)

Eren Ers&#246;nmez
Eren Ers&#246;nmez

Reputation: 39085

var freqs = File.ReadAllText("myfile.txt")
                    .Where(c => Char.IsLetter(c))
                    .GroupBy(c => c)
                    .ToDictionary(g => g.Key, g => g.Count());

This should give you a Dictionary of characters and their count.

Update:

If you want case insensitive counts, just change the GroupBy:

.GroupBy(c => Char.ToUpper(c)) // instead of .GroupBy(c => c)

And in my opinion a dictionary is better than an array in this case because the character that the "count" belongs to is not just implied by the index; instead, it is an explicit key. This makes lookups easier because you don't have to convert the character to an index. Additionally, this makes it more flexible when adding internationalization support. However, if you absolutely need an array, it is a simple change:

var freqs = File.ReadAllText("myfile.txt")
                    .Where(c => Char.IsLetter(c))
                    .GroupBy(c => c)
                    .OrderBy(g => g.Key) 
                    .Select(g => g.Count())
                    .ToArray()

Upvotes: 6

Alvin Wong
Alvin Wong

Reputation: 12420

I spent quite a while to figure out this Linq which will result in the exact same array you want:

int[] occurance = File.ReadAllText("myfile.txt")
                  .Where(c => char.IsLetter(c))
                  .Select(c => (int)char.ToUpperInvariant(c) - 65)
                  .GroupBy(a => a)
                  .ToDictionary(a => a.Key, a => a.Count())
                  .OrderBy(a => a.Key)
                  .Select(a => a.Value)
                  .ToArray();

Upvotes: 0

Jim Mischel
Jim Mischel

Reputation: 133995

A few modifications to your code will make it work, assuming that you only want to count the letters 'A' through 'Z':

int counter = 0;
int[] freq = new int[26]; // create frequency array

// counts frequency
while (counter < inValue.Length)
{
    char c = invalue[counter];
    if (c >= 'A' && c <= 'Z')
    {
        ++freq[(int)c - 65]
    }
    ++counter;
}

If you want to count lower case letters as well, then change the first line in the loop to:

char c = char.ToUpper(invalue[counter]);

Upvotes: 0

Rahul Tripathi
Rahul Tripathi

Reputation: 172448

You can try something like this. This worked for me but I didnt used StreamReader:-

   int[] c = new int[(int)char.MaxValue];

string s = File.ReadAllText("text.txt");

foreach (char t in s)
{
    c[(int)t]++;
}

for (int i = 0; i < (int)char.MaxValue; i++)
{
    if (c[i] > 0 &&
    char.IsLetterOrDigit((char)i))
    {
    Console.WriteLine("Letter: {0}  Frequency: {1}",(char)i, c[i]);
    }
}

Upvotes: 1

Related Questions