Loops and arrays

Basically what I am trying to do, is read in from a text file character by character, and count the frequency of each alphabetic character. then output the results to the screen, but of course it isn't working, and i know of no one experienced enough to help me out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <cctype>  
using namespace std;

void displayArray(int array[], int size);

int main()
{
    ifstream input;
    
    input.open("data.txt");
    if(input.fail())
    {
        cout<<"Error opening file"<<endl;
        system("pause");
        return 0;
    }    
    char letter[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    int frequency[26]={0};
    char ch;
    int count=0;
    for (int i=0 ;i<26; i++)
    {
       while(!input.eof())
       {
       input.get(ch);
       if(isalpha(ch)&&tolower(ch)==letter[i])
       count++;
       }
       frequency[i]=count;
       count=0;
    }  
    
    displayArray(frequency,5);// i'm meant to display the top 5 frequencies but    i haven't got to that stage yet, also not sure what to do there either. so atm i'm just displaying the count for the first 5 a b c d e.
    
    system("pause");
    return 0;
}

void displayArray(int array[], int size)
//displays the array
{
   for(int i=0; i<size; i++)
   {
      cout<<array[i]<<" ";
   }
   cout<<endl;
}  


my data.text is just a simple text file with "abcdeaaa", for the first value i get 4 which is correct, but after that everything is 0 :/, ive tried reseting the counter elsewhere in the loop, but have ended up all fours instead or some other horrible thing.

a little help would be greatly appreciated as i just cant seem to wrap my head around this.
Last edited on
get rid of your count variable - the frequency array is meant to take care of this

if you fix the block from Line 23 - 34, you should be able to get this working

also, the loop on Lines 24-25, 34 is not needed - if you use

int idx = tolower( ch ) - 'a';

you can use idx to index right into frequency[], assuming that your input is A-Z,a-z

if you are still having problems after trying this, post your new code
Last edited on
I kind of understand what you are saying, I am just not sure of how to do it.

1
2
3
4
5
6
7
8
9
    for (int i=0 ;i<26; i++)
    {
       while(!input.eof())
       {
       input.get(ch);
       if(isalpha(ch)&&tolower(ch)==letter[i])
       frequency[i]+=1;
       } 
    } 



although that has just got me right back where i started, as the first reads letter outputs to 4 while the rest are 0

im not quite sure on the indexing part, i understand somewhat of what you are trying to say, I can kinda see it, subtracting the 'a' away which would give me a value between 0-25 which i then use to point to a box in my array to add 1 to to increase the frequency.

I think anyway, not exactly too sure on how to arrange that tho.

Are you using/modifying someone else's code? That's ok, but you need to understand what it's doing.

Try replacing that chunk with:

1
2
3
4
5
while(!input.eof())
{
  input.get( ch );
  frequency[ tolower( ch ) - 'a' ]++;
} 


but make sure you understand this code before using it (otherwise, you will be bitten by its limitations).
No this is my own code i've written from scratch, I wont learn by copying after all

ah thats it, I see what i had done wrong, Still getting used to the difference between what makes logical sense in my head, and what makes logical sense to the computer. I can move onto finishing it off the rest of it now.

Thank you very much.

np - just a hint for your last part where you intend to display your top 5 frequencies

there are various ways of doing this, but whatever you decide to do, it's probably a good idea to use another data structure to hold those top 5 - OTOH, it's a mini-challenge, but you could also try to sort them in-place, meaning sort frequency[] and letter[] concurrently

anyhow, gl and feel free to post if you need help
thank you for the hints, altho I have to admit, its one road bump after the other. ive got a selection sort set up with various functions, but how to sort both concurrently ive no idea. I can sort the frequency but pairing it to letters is obviously the tricky part.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
void selectionSort(int array[], int size)
//performs a selection sort on array
{
   for(int i=0; i<size-1; i++)
   {
      swap(array, indexOfSmallestStartingFrom(array, size, i), i);
   }
}

int findSmallest(int array[], int size)
//finds the smallest value in the array
{
   int smallestSoFar=array[0];
   for(int i=1; i<size; i++)
   {
      if(array[i]<smallestSoFar)
         smallestSoFar=array[i];
   }
   return smallestSoFar;
}
int indexOfSmallestStartingFrom(int array[], int size, int start)
//returns the index of the first smallest value in the array
//starting from index start
{
   int smallestSoFar=array[start];
   int indexSmallestSoFar=start;
   
   for(int i=start; i<size; i++)
   {
      if(array[i]<smallestSoFar)
      {
         smallestSoFar=array[i];
         indexSmallestSoFar=i;
      }
   }
   return indexSmallestSoFar;
}


int indexOfSmallest(int array[], int size)
//returns the index of the first smallest value in the array
{
   int smallestSoFar=array[0];
   int indexSmallestSoFar=0;
   
   for(int i=1; i<size; i++)
   {
      if(array[i]<smallestSoFar)
      {
         smallestSoFar=array[i];
         indexSmallestSoFar=i;
      }
   }
   return indexSmallestSoFar;
}



void swap(int array[], int index1, int index2)
//swaps the items at index1 and index2
{
   int temp=array[index1];
   array[index1]=array[index2];
   array[index2]=temp;
}


coding a selection sort for one array was easy, but doing both concurrently im not sure about. maybe combining the functions and then when the index's are swapped in the frequency[], i set it up to swap the corresponding indexs in the letter[]. but then that seems like alot of code to be messing around with.

Last edited on
suppose i and j are the indexes that you find that need to be swapped

then swap both i and j in frequency[] and in letter[]

if you do so with a sort in descending order, then
frequency[0..4] will contain descending frequencies
letter[0..4] will contain the letters that correspond to those frequencies

PS - don't worry about those road bumps - we all go through them when we pick up new languages and libraries - you will do fine as long as you think on your own a bit, practice, and learn
so i was on the right track then. I'll get to it, hopefully everything will work out smoothly...

I try to do as much on my own as possible, but id say Ive come reasonably far in only 6 weeks.

but thank you again.
np - no need to thank me any more - your learning something makes it worthwhile

sry about that, I was jumping around so much that I didn't read your code! you are doing extremely well for 6 weeks, btw (much better than I)!

you are 99% of the way there already!

I can think two approaches

Approach A (quick but a bit sloppy) - quick as in "done in a few minutes"
1. just modify Line 1 to accept a second array called array2
2. Line 6 - save your return value from indexOfSmallestStartingFrom() into variable j
3. add a line after Line 6 which swaps array2 using i and j

Approach B - requires reworking of the original code and the sort code
1. instead of 2 arrays, put letter and frequency into a struct and have an array of these structs
2. modify your selection sort to be template based, accepting your struct as a template parameter

Approach B is much more professional but requires an understanding of structs (not hard - it's just a record grouping related data together) and templates (a bit tougher, but very useful).

Perhaps you can make a copy and do A now and B later, when you learn structs and templates.
Approach A was exactly what i was thinking, but i seem to of smegged that up somehow, the letters are not matching the frequency, well they are in some cases but mostly not.

in the main function
1
2
3
4
selectionSort(frequency,26,letter);

    for (int i=0; i < 5; i++)
    cout << letter[i] << " = " << frequency[i] <<endl;


and inside the functions
1
2
3
4
5
6
7
8
9
10
void selectionSort(int array[], int size, char array2[])
//performs a selection sort on array
{
   for(int i=0; i<size-1; i++)
   {
    int j=indexOfSmallestStartingFrom(array, size, i);
    charswap(array2,j,i);
    swap(array,j, i);
   }
}


I added charswap, which is
1
2
3
4
5
6
7
void charswap(char array[], int index1, int index2)

{
   int temp=array[index1];
   array[index1]=array[index2];
   array[index2]=temp;
}


but somehow something has gone wrong. sloppy indeed.

when i restrict the loop to showing five i get problems, if i let it be the full 26 i get the correct results, but then im left with 26 results when i only want the top 5 highest frequencies
Last edited on
post the entire code and I will have a look - something doesn't look right on Line 8 - it might be a copy-and-paste issue

anyhow, repost your entire new code
actually I fixed it.

the way it is sorted in descending order, which means I wanted the last five places, instead of the first five which i was asking for
1
2
3
4
selectionSort(frequency,26,letter);

    for (int i=0; i < 5; i++)
    cout << letter[i] << " = " << frequency[i] <<endl;


so with a few adjustments
1
2
3
4
selectionSort(frequency,26,letter);

    for (int i=21; i < 26; i++)
    cout << letter[i] << " = " << frequency[i] <<endl;


im able to get the correct five.

just the only problem I have now, is that they are in descending order, when really i want the first five in ascending order
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <iostream>
#include <cstdlib>
#include <fstream>
#include <cctype>  
using namespace std;

void selectionSort(int array[], int size, char array2[]);
int indexOfSmallestStartingFrom(int array[], int size, int start);
void swap(int array[], int index1, int index2);
int findSmallest(int array[], int size);
int indexOfSmallest(int array[], int size);
void charswap(char array[], int index1, int index2);

int main()
{
    ifstream input;
    
    input.open("data.txt");
    if(input.fail())
    {
        cout<<"Error opening file"<<endl;
        system("pause");
        return 0;
    }    
    char letter[26]={'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
    int frequency[26]={0};
    char ch;
       while(!input.eof())
       {
       input.get( ch );
       frequency[ tolower( ch ) - 'a' ]++;
       } 
    
selectionSort(frequency,26,letter);

    for (int i=21; i < 26; i++)
    cout << letter[i] << " = " << frequency[i] <<endl;
    
    system("pause");
    return 0;
}



void selectionSort(int array[], int size, char array2[])
//performs a selection sort on array //void swap(int array[], int index1, int index2)
{
   for(int i=0; i<size-1; i++)
   {
    int j=indexOfSmallestStartingFrom(array, size, i);
    charswap(array2,j,i);
    swap(array,j, i);
   }
}

int findSmallest(int array[], int size)
//finds the smallest value in the array
{
   int smallestSoFar=array[0];
   for(int i=1; i<size; i++)
   {
      if(array[i]<smallestSoFar)
         smallestSoFar=array[i];
   }
   return smallestSoFar;
}
int indexOfSmallestStartingFrom(int array[], int size, int start)
//returns the index of the first smallest value in the array
//starting from index start
{
   int smallestSoFar=array[start];
   int indexSmallestSoFar=start;
   
   for(int i=start; i<size; i++)
   {
      if(array[i]<smallestSoFar)
      {
         smallestSoFar=array[i];
         indexSmallestSoFar=i;
      }
   }
   return indexSmallestSoFar;
}


int indexOfSmallest(int array[], int size)
//returns the index of the first smallest value in the array
{
   int smallestSoFar=array[0];
   int indexSmallestSoFar=0;
   
   for(int i=1; i<size; i++)
   {
      if(array[i]<smallestSoFar)
      {
         smallestSoFar=array[i];
         indexSmallestSoFar=i;
      }
   }
   return indexSmallestSoFar;
}

void swap(int array[], int index1, int index2)
//swaps the items at index1 and index2 in a int array
{
   int temp=array[index1];
   array[index1]=array[index2];
   array[index2]=temp;
}

void charswap(char array[], int index1, int index2)
//swaps the items at index1 and index2 in a char array
{
   int temp=array[index1];
   array[index1]=array[index2];
   array[index2]=temp;
}


so I just need to swap a few things around to get it to sort the other way correct ? then using the first loop i had it should be from highest frequency to lowest down the console, instead of the lowest top five first and the highest at the bottom
Last edited on
woohoo - gratz - a little hacky but a job well done!

here's a gift, if you haven't figured it out already:

for (int i=25; i>20; --i)

now, go do the template version - just kidding
Last edited on
its not perfect, but it does the job, later on after a little more learning ill be sure to come back and improve on it.

ah of course, always the simple things you overlook. thank you

ahaha, I think ive given enough time to my c++ for the day already.
Topic archived. No new replies allowed.