Keeping Tally of Characters in Arrays - c++

I'm working on a Caesar Cipher program for an assignment and I have the general understanding planned out, but my function for determining the decipher key is unnecessarily long and messy.
while(inFile().peek != EOF){
inFile.get(character);
if (character = 'a'|| 'A')
{ aCount++; }
else if (character = 'b' || 'B')
{ bCount++; }
so on and so on.
What way, if it's possible, can I turn this into an array?

You can use the following code:
int count [26] = {0};
while(inFile().peek != EOF){
inFile.get(character);
if (int (character) >=65 || int (character) <=90)
{ count [(int (character)) - 65] ++; }
else if (int (character) >=97 || int (character) <=122)
{ count [(int (character)) - 97] ++; }
}
P.S. This is checking for the ASCII value of each character and then increment its respective element in the array of all characters, having 0 index for A/a and 1 for B/b and so on.
Hope this helps...
P.S. - There was an error in your code, = is an assignment operator and == is a conditional operator and you do not assign value in if statement, you check for condition... So always use == to check for equality...

You can use an array in the following manner
int letterCount['z'] = {0}; //z is the highest letter in the uppercase/lowercase alphabet
while(inFile().peek != EOF){
inFile.get(character);
if (character > 'A' && character < 'z')
letterCount[character]++;
}
You can also use a hashmap like this
#include <unordered_map>
std::unordered_map<char,int> charMap;
while(inFile().peek != EOF){
inFile.get(character);
if (charMap.find(character) == charMap.end())
charMap[character] = 1;
else
charMap[character] = charMap[character] + 1;
}
In case you do not know, a hashmap functions as an array, where the index can be any class you like, as long as it implements a hash function.

Related

Extracting int from String on Arduino

I have a buffer of random characters streaming into my Arduino from a XBee module. I want to extract the first integer that it sees (will be <= 3-digit int if that makes a difference), then move on with that number and stop looking at the rest of the incoming characters.
For reference, I'm trying to use this as part of a 2-way handshake with a node.js server that doesn't get messed up when other Arduinos are also attempting to handshake or are already connected and sending data.
I think I have a way that might work to extract an int, but it seems really ugly, so I'm thinking there must be a much shorter/cleaner way to go about this. Here's my very long code to do something that's probably pretty simple:
String intString = "";
int intStart = 0;
for (int i = 0; i < msg.length(); i++) {
while (intStart != 2) {
if (intStart == 0) {
if ((msg[i] == '0') || (msg[i] == '1') || (msg[i] == '2') ||
(msg[i] == '3') || (msg[i] == '4') || (msg[i] == '5') ||
(msg[i] == '6') || (msg[i] == '7') || (msg[i] == '8') ||
(msg[i] == '9')) {
intString += msg[i];
intStart = 1;
}
}
// previous int, next is still int
if (intStart == 1) {
if ((msg[i] == '0') || (msg[i] == '1') || (msg[i] == '2') ||
(msg[i] == '3') || (msg[i] == '4') || (msg[i] == '5') ||
(msg[i] == '6') || (msg[i] == '7') || (msg[i] == '8') ||
(msg[i] == '9')) {
intString += msg[i];
intStart = 1;
}
}
// previous int, next is not int
else if ((msg[i] != '0') && (msg[i] != '1') && (msg[i] != '2') &&
(msg[i] != '3') && (msg[i] != '4') && (msg[i] == '5') &&
(msg[i] != '6') && (msg[i] != '7') && (msg[i] == '8') &&
(msg[i] != '9')) {
intStart = 2;
}
}
}
int number = intString.toInt();
Serial.println(number);
Any suggestions/advice is greatly appreciated.
Rather than compare against every number from 0 to 9, use the standard C function isdigit().
String intString = "";
int intStart = 0;
for (int i = 0; i < msg.length(); i++) {
while (intStart != 2) {
if (intStart == 0) {
if (isdigit(msg[i])){
intString += msg[i];
intStart = 1;
}
}
// previous int, next is still int
if (intStart == 1) {
if (isdigit(msg[i])) {
intString += msg[i];
intStart = 1;
}
}
// previous int, next is not int
else if ( isdigit(msg[i]) ) {
intStart = 2;
}
}
}
"Rubber duck debugging":
Let's assume the first char of the msg is a digit:
set intStart to 0
take the first char of the msg
while intStart is not yet 2
if intStart is 0 (it is, we haven't adjusted it) and the first char of the msg is digit (we assumed it is), then append the first char to intString and make intStart = 1
if intStart == 1 (it is, we set it at the prev step) and the first char of the msg is digit (it is still the first, i didn't change), then append the first char to intString (great, now I have it twice) and set intStart=1 (hey, intStart didn't change). Else... well, we can ignore else, we are in the good conditions for then
so back to the step 3, with the intStart==1 and i still 0 and the first char of the msg still a digit.
Should I continue or are you able to do it?
In essence, with the first char of the msg a digit, you'll never get out from while (intStart != 2) until you run out of heap-space due to intString growing by repeating the same fisrt char all over.
Is that what you want?
Is it so hard to explain this to your rubber duck before asking SO?(yes, I understand, Arduino doesn't have a debugger, but you still can use Serial.print)
[Update on the comments]
Sorry if I was unclear, but it doesn't necessarily start with an integer, the integer could be in the middle of the char buffer.
The first sequence of digits in the char buffer of any length (really doesn't have to be restricted to max 3-digit, only if it makes it easier)
So, before stating to collect, we just need to position ourselves on the first digit of the string buffer
int startScan=0;
// no body for the cycle, everything works just from
// the exit condition and increment
for(
;
startScan < msg.length() && ! isdigit(msg[i]); // as long as it's not a digit
startScan++
);
// from this position, start collecting for as long as we have digits
int intValue=0;
String intString;
for(; startScan < msg.length() && isdigit(msg[startScan]); startScan++) {
intString += msg[startScan]; // take it inside the string
// careful with this one, it may overflow if too many digits
intValue = intValue*10 + (msg[startScan]-'0');
}
// if we reached here with an empty intString, we didn't find any digits
If you don't need the intString, just the intValue, don;t use the intString - at most a bool hasDigits to init to false and set to true in place of intString += msg[startScan]; (to act as a signal for the 'no digits encountered' case).
If you don't need the intValue, just wipe out from the code anithing that uses it.
So, if my understating is correct, you have the following problem:
I have a String message which starts by at most 3 decimal digits and ends possibly with other info I don't need. I want that 'at most 3 digits' prefix transformed in an integer for me to use further
If this is you problem, then try this:
int intValue=0;
String intString;
int maxLookInto=(msg.length() > 3 ? 3 : msg.length()); // at most 3 digits
for(int i=0; i<maxLookInto && isdigit(msg[i]); i++) {
// if we got here, we know msg[i] is still a digit, otherwise
// we get out of cycle ealier
intString += msg[i]; // take it inside the string
intValue = intValue*10 + (msg[i]-'0'); // transforming in base 10 in an int
}
// Do what you like with either intString (textual representation of the
// at-most-3-digits or with the same value converted already to a number
// in intValue
If Arduino doesn't have the isdigit function available, you can implement your own like
int isdigit(char c) {
// we are using ASCII encoding for characters, aren't we?
return (c>='0' && c <='9');
}
One way is to use the String object. This has a toInt method.
BTW there is an Arduino specific stack exchange. arduino.stackexchange.com

strcmpi integer without a cast error

I'm trying to create a program that removes vowels from a string, add them into a vector and then give the user the possibility of having the original code again.
In my code i have this:
char s[20];
And soon after i have this comparison:
for(j=0;j<tam;j++)
{
if(strcmpi(s[j],"a")==1 ||
(strcmpi(s[j],"e")==1 ||
(strcmpi(s[j],"i") ==1||
(strcmpi(s[j],"o") ==1||
(strcmpi(s[j],"u")==1))
{
So if the array is char and the vowels are char(""), why the compiler give me this error?:
[Warning] passing arg 1 of `strcmpi' makes pointer from integer without a cast
EDIT
As someone said the correct is s[j] == 'a', but that result in wrong way. If a put car the result is still car. Don't know why.
if(s[j] == 'a' ||
s[j] == 'A' ||
s[j] == 'e' ||
s[j] == 'E' ||
s[j] == 'i' ||
s[j] == 'I' ||
s[j] == 'o' ||
s[j] == 'O' ||
s[j] == 'u' ||
s[j] == 'U')
{
s[j] = s[j++]; }
Strcmpi is for comparing strings. The first argument to strcmpi is of type char, when it expects a char*.
In order to compare single chars, s[j]=='e' is enough, or tolower(s[j])=='e' if you need it to be case insensitive. You'll need to include ctype.h. for tolower.
The arguments to strcmpi must be strings, but s[j] is just a single character, not a string. You can use == to compare characters directly. To get case-insensitive comparisons, get the lowercase version of the character first and compare it.
for (j = 0; j < tam; j++) {
char lower = tolower(s[j]);
if (lower == 'a' || lower == 'e' || lower == 'i' || lower == 'o' || lower == 'u') {
...
}
}
You don't want to use strcmp or any of its variants.
Because you want to know whether the string contains vowels or not, you may want to use a substring search using strstr.
You use function strcmpi incorrectly. It first parameter has type const char * while you pass an argument of type char. That is the function expects a string while you pass only one character.
Moreover this function is not a standard C/C++ function. So it should not be used.
You could achieve the same result using the following approach
char vowels[] = "aeiou";
//...
if ( strchr( vowels, tolower( s[j] ) )
{
std::cout << s[j] << " is a vowel" << std::endl;
}
You have already been told that strcmpi is not the right way to check single characters. This is an answer to the edit to your question, where you ask about actually stripping the vowels.
If you want to retain the original string, you need extra memory for the string without consonants. You also need two indices, because once you have skipped a vowel in the original string, the indices are out of sync. Here's an example implementation:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
char orig[] = "Jackdaws love my big sphinx of quartz.";
char cons[sizeof(orig)]; // Make new char buffer as big
// as the original
int i, j;
j = 0;
for (i = 0; orig[i]; i++) {
if (strchr("AEIOUaeiou", orig[i]) == NULL) {
cons[j++] = orig[i];
}
}
cons[j] = '\0'; // Terminate consonant string
printf("was: '%s'\n", orig);
printf("is: '%s'\n", cons);
return 0;
}
The expression strchr checks whether a character is in a string. You can use it as a shortcut to spelling out all vowels in explicit comparisons.

C++ manipulating numbers in ASCII to stay only in range of letters

#include <iostream>
using namespace std;
Int main() {
cout<<"Give me a letter" <<endl;
char letter;
cin>>letter;
cout<<letter;
(Int)letter;
letter+=2;
cout<<(char)letter;
(Int)letter;
letter-=25;
cout<<(char)letter;
return 0;
}
How would I manipulate the numbers in a way so that the numbers will always output a letter.
ie: if the letter z was chosen and adding 2 is a symbol how would I manipulate it in a way so that it will always stay between the numbers for capital numbers and uncapitalized numbers. Thanks. Please try to keep answers at a beginner level please I am new to this.
if(letter > 'z') {
//do stuff
}
if(letter < 'a' && letter > 'Z') {
//do stuff
}
if(letter < 'A') {
//do stuff
}
It just depends on how you want to handle the character when it goes into one of the three ranges on the ASCII chart in which the characters are not letters.
As a side note, you don't have to cast a char to an int to do math with it.
char myChar = 'a' + 2;
cout << myChar;
This will print: c
c has an ASCII value of 2 more than a.
The surest method is to use a table for each category, and do
your arithmetic on its index, modulo the size of the table.
Thus, for just lower case letters, you might do something like:
char
transcode( char original )
{
char results = original;
static std::string const lower( "abcdefghijklmnopqrstuvwxyz" );
auto pos = std::find( lower.begin(), lower.end(), results );
if ( pos != lower.end() ) {
int index = pos - lower.begin();
index = (index + 2) % lower.size();
results = lower[ index ];
}
return results;
}
This solution is general, and will work regardless of the sets
of letters you want to deal with. For digits (and for upper and
lower case, if you aren't too worried about portability), you
can take advantage of the fact that the code points are
contiguous, and do something like:
char
transcode( char original )
{
char results = original;
if ( results >= '0' && results <= '9' ) {
char tmp = results - '0'
tmp = (tmp + 2) % 10;
results = tmp + '0';
}
return results;
}
An alternative implementation would be to use something like:
results = results + 2;
if ( results > '9' ) {
results -= 10;
}
in the if above. These two solutions are mathematically
equivalent.
This is only guaranteed to work for digits, but will generally
work for upper or lower case if you limit yourself to the
original ASCII character set. (Be aware that most systems today
support extended character sets.)
You can test directly against ASCII chars by using 'x' notation. Further, you can test things together using && ("and" respectively"):
if ('a' <= letter && letter <= 'z') {
// Letter is between 'a' and 'z'
} else if ('A' <= letter && letter <= 'Z')) {
// Letter is between 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}
Or you can use the standard library function std::isalpha which handles this for you:
if (std::isalpha(letter)) {
// Letter is between 'a' and 'z' or 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}

Counting the frequency of characters in a file. C++

The task is to print the (given text file) encountered Latin characters using the frequency table (without distinguishing between uppercase and lowercase letters) to file f1. The table must be sorted alphabetically.
So far my program only counts the letter A. I'm having problems with creating the loops which go through the whole alphabet and prints the table into another file, could you help me with those?
#include <stdio.h>
const char FILE_NAME[] = "yo.txt";
#include <stdlib.h>
#include <iostream>
using namespace std;
int main() {
int count = 0; /* number of characters seen */
FILE *in_file; /* input file */
/* character or EOF flag from input */
int ch;
in_file = fopen(FILE_NAME, "r");
if (in_file == NULL) {
printf("Cannot open %s\n", FILE_NAME);
system("Pause");
exit(8);
}
while (1) {
char cMyCharacter = 'A';
int value = (int)cMyCharacter;
ch = fgetc(in_file);
if (ch == EOF){
break;
}
int file_character = (int) ch;
if (file_character == value || file_character == value+ 32) {
count++;
}
}
printf("Number of characters in %s is %d\n", FILE_NAME, count);
char cMyCharacter = 'A';
int iMyAsciiValue = (int)cMyCharacter;
cout << iMyAsciiValue;
system("Pause");
fclose(in_file);
return 1;
}
First, get an array of size 26 for frequencies of a to z
int freq[26] = {0};
freq[0] for 'a', freq[1] for 'b', etc.
Second, change
if (file_character == value || file_character == value+ 32)
to
if (file_character >= 'a' && file_character <= 'z')
for all the lower-case alphabets (i.e. 'a' to 'z').
Third, get index and count by
freq[file_character - 'a']++;
, file_character - 'a' calculates the index, and the rest does count.
Fourth, print the freq array.
Fifth, add
else if (file_character >= 'A' && file_character <= 'Z')
for upper-case characters, and change subsequent codes accordingly.
It is your homework, you should try to figure out the whole program yourself. I hope this answer provides enough hints for you.

How to convert a recursive solution to bottom up or top down solution?

I am solving this problem-
Given a string consisting of a,b and c's, we can take any two adjacent
distinct characters and replace it with the third character. For
example, if 'a' and 'c' are adjacent, they can replaced with 'b'. What
is the smallest string which can result by applying this operation
repeatedly?
Now I have written the following recursive solution (far from efficient), but want to convert it to either top-down or bottom-up solution.
Problem: I am not able to come up with a tabular structure for memoization. Even though I have to output only the length of resulting string, how can I solve it without actually solving the problem. The strings are getting reduced, so how do I store them?
Any hint for DP solution or Memoization would be great!
EDIT Many people have come up with top-down memoization solution, please try bottom-up as well.
#include <iostream>
#include <string>
using namespace std;
string reduce(string s)
{
if (s.length() <= 1)
return s;
int k;
char c = s[0];
string min = s;
for (k = 1; k < s.length() && c; ++k)
if (s[k] != c)
c = 0;
if (c)
return s;
if (s.length() == 2){
if (s[0] != 'a' && s[1] != 'a')
s[0] = 'a';
else if (s[0] != 'b' && s[1] != 'b')
s[0] = 'b';
else if (s[0] != 'c' && s[1] != 'c')
s[0] = 'c';
s.resize(1);
return s;
}
for (k = 1; k < s.length(); ++k){
string s1 = reduce(s.substr(0, k));
string s2 = reduce(s.substr(k));
if (s1.length() + s2.length() < min.length())
min = s1 + s2;
if (!s1.empty() && !s2.empty() && s1.back() != s2.front()){
if (s1.back() != 'a' && s2.front() != 'a')
s1.back() = 'a';
else if (s1.back() != 'b' && s2.front() != 'b')
s1.back() = 'b';
else if (s1.back() != 'c' && s2.front() != 'c')
s1.back() = 'c';
s1 = reduce(s1 + s2.substr(1));
if (s1.length() < min.length())
min = s1;
}
}
return min;
}
int main()
{
string input;
cin >> input;
cout << reduce(input) << endl;
return 0;
}
I'm a bit too lazy to think the problem through, but I'll give you an approach to memoization that often enough works.
Instead of recursing directly, introduce mutual recursion.
std::string reduce(std::string const &s)
{
// ...
string s1 = reduce_memo(s.substr(0, k));
string s2 = reduce_memo(s.substr(k));
// ...
}
where reduce_memo maintains a hash table, i.e. an unordered_map, mapping subproblems to their solutions.
// static is incredibly ugly, but I'll use it here for simplicity
static std::unordered_map<std::string, std::string> memo;
std::string reduce_memo(std::string const &s)
{
try {
return memo.at(s);
} except (std::out_of_range const &) {
std::string r = reduce(s);
memo[s] = r;
return r;
}
}
When programming in C++98, use std::map instead of unordered_map.
This doesn't solve the problem, but I noticed:
if (s.length() == 2){
if (s[0] != 'a' && s[1] != 'a')
s[0] = 'a';
else if (s[0] != 'b' && s[1] != 'b')
s[0] = 'b';
else if (s[0] != 'c' && s[1] != 'c')
s[0] = 'c';
s.resize(1);
return s;
}
doesn't work according to the problem statement:
we can take any two adjacent distinct characters and replace it with the third character.
Consider the string s = "bb". Neither s[0] nor s[1] are equal to 'a', which means the condition s[0] != 'a' && s[1] != 'a' will evaluate to true for the string "bb". This goes for any string of consecutive characters of the same value, e.g. "bb", "cc".
Perhaps in the condition you can take the difference of the two consecutive characters, and check if they're non-zero.
You can memoize your solution by storing the result of reduce(s) in a map<string,string>.
string reduce(string s, map<string,string>& memo) {
if (memo.count(s)) {
return memo[s];
}
// The rest of your code follows...
memo[s] = min;
}
Whatever i have understood from the problem the solutions should be
length of the input - if all input characters are same like
aaaaa - 5
bbb - 3
and 1 in every other case.
Correct me if I miss some part of the problem.
The absolute minimum is 1. However, the specifics of the string and replacement rules may yield between 1 and n, where n is the length of the string.
For the specific example, then the smallest possible is n/2, as you take 2 characters and replace them with 1 (which cannot be further replaced) so even if you had "acacacacacacacac", the best possible case, you would still only achieve the factor of 2 reduction.
I solved a similar problem in competitive programming workshop,
and indeed your proposed solution weren't fast enough.
My solution was creating such vector:
string s;
cin >> s;
int length = s.length();
vector<vector<int> > v(length, vector<int>(length)); // 2d array of size length*length.
where v[i][j] will be the minimal length the substring from i to j of s can get to.
Later all you have to do is fill this table in increasing size.
Hope that helped.
"a...a" (“a" * n) == > n
"b...b" (“b" * n) == > n
"c...c" (“c" * n) == > n
any other ==> 1 or 2 with my greedy algorithm.
If we get 2 in this greedy algorithm, I can't prove it is the smallest result for the input string.
Greedy algorithm
while the last two is the same character { // the number of the same characters
find the last replaceable pair // at the tail will decrease until
reduce them // it become 1
}
while find the first replaceable pair
reduce them