How to make sure user enters allowed enum - c++

I have to write a program with an Enum state, which is the 50 2-letter state abbreviations(NY, FL, etc). I need to make a program that asks for the user info and they user needs to type in the 2 letters corresponding to the state. How can I check that their input is valid i.e matches a 2 letter state defined in Enum State{AL,...,WY}? I suppose I could make one huge if statement checking if input == "AL" || ... || input == "WY" {do stuff} else{ error input does not match state }, but having to do that for all 50 states would get a bit ridiculous. Is there an easier way to do this?
Also if Enum State is defined as {AL, NY, FL}, how could I cast a user input, which would be a string, into a State? If I changed the States to {"AL", "NY", "FL"} would that be easier or is there another way to do it?

Unfortunately C++ does not provide a portable way to convert enum to string and vice versa. Possible solution would be to populate a std::map<std::string,State> (or hash map) and on conversion do a lookup. You can either populate such map manually or create a simple script that will generate a function in a .cpp file to populate this map and call that script during build process. Your script can generate if/else statements instead of populating map as well.
Another, more difficult, but more flexible and stable solution is to use compiler like llvm and make a plugin that will generate such function based on syntax tree generated by compiler.

The simplest method is to use an STL std::map, but for academic exercises that may not be permitted (for example it may be required to use only techniques covered in the course material).
Unless explicitly initialised, enumerations are integer numbered sequentially starting from zero. Given that, you can scan a lookup-table of strings, and cast the matching index to an enum. For example:
enum eUSstate
{
AL, AK, AZ, ..., NOSTATE
} ;
eUSstate string_to_enum( std::string inp )
{
static const int STATES = 50 ;
std::string lookup[STATES] = { "AL", "AK", "AZ" ... } ;
int i = 0 ;
for( i = 0; i < STATES && lookup[i] != inp; i++ )
{
// do nothing
}
return static_cast<eUSstate>(i) ;
}
If perhaps you don't want to rely on a brute-force cast and maintaining a look-up table in the same order as the enumerations, then a lookup table having both the string and the matching enum may be used.
eUSstate string_to_enum( std::string inp )
{
static const int STATES = 50 ;
struct
{
std::string state_string ;
eUSstate state_enum ;
} lookup[STATES] { {"AL", AL}, {"AK", AK}, {"AZ", AL} ... } ;
eUSstate ret = NOSTATE ;
for( int i = 0; ret == NOSTATE && i < STATES; i++ )
{
if( lookup[i].state_string == inp )
{
ret = lookup[i].state_enum ;
}
}
return ret ;
}
The look-up can be optimised by taking advantage of alphabetical ordering and performing a binary search, but for 50 states it is hardly worth it.

What you need is a table. Because the enums are linear,
a simple table of strings would be sufficient:
char const* const stateNames[] =
{
// In the same order as in the enum.
"NY",
"FL",
// ...
};
Then:
char const* const* entry
= std::find( std::begin( stateNames ), std::end( stateNames ), userInput );
if (entry == std::end( stateNames ) ) {
// Illegal input...
} else {
State value = static_cast<State>( entry - std::begin( stateNames ) );
Alternatively, you can have an array of:
struct StateMapping
{
State enumValue;
char const* name;
struct OrderByName
{
bool operator()( StateMapping const& lhs, StateMapping const& rhs ) const
{
return std::strcmp( lhs.name, rhs. name ) < 0;
}
bool operator()( StateMapping const& lhs, std::string const& rhs ) const
{
return lhs.name < rhs;
}
bool operator()( std::string const& lhs, StateMapping const& rhs ) const
{
return lhs < rhs.name;
}
};
};
StateMapping const states[] =
{
{ NY, "NY" },
// ...
};
sorted by the key, and use std::lower_bound:
StateMapping::OrderByName cmp;
StateMapping entry =
std::lower_bound( std::begin( states ), std::end( states ), userInput, cmp );
if ( entry == std::end( states ) || cmp( userInput, *entry) {
// Illegal input...
} else {
State value = entry->enumValue;
// ...
}
The latter is probably slightly faster, but for only fifty
entries, I doubt you'll notice the difference.
And of course, you don't write this code manually; you generate
it with a simple script. (In the past, I had code which would
parse the C++ source for the enum definitions, and generate the
mapping functionality from them. It's simpler than it sounds,
since you can ignore large chunks of the C++ code, other than
for keeping track of the various nestings.)

The solution is simple, but only for 2 characters in the string (as in your case):
#include <stdio.h>
#include <stdint.h>
enum TEnum
{
AL = 'LA',
NY = 'YN',
FL = 'LF'
};
int _tmain(int argc, _TCHAR* argv[])
{
char* input = "NY";
//char* input = "AL";
//char* input = "FL";
switch( *(uint16_t*)input )
{
case AL:
printf("input AL");
break;
case NY:
printf("input NY");
break;
case FL:
printf("input FL");
break;
}
return 0;
}
In above example I used an enumeration with a double character code (it is legal) and passed to the switch statement a input string. I tested it end work!. Notice the word alignment in enumeration.
Ciao

Related

find if string starts with sub string using std::equal

May you please point me to what is the wrong thing I am doing here?
auto is_start_with = [](std::string const& whole_string, std::string const& starting_substring)->bool{
if (starting_substring.size() > whole_string.size()) return false;
return std::equal(begin(starting_substring), end(starting_substring), begin(whole_string));
};
It is always return true.
I know there is many many other solutions but I want to know what is the error here.
EDIT :
Debuging!
P.S. I tried it in other main file with directly entering the strings and it worked!!
Edit 2:
I deleted two to lower transforms before the comparison and it worked!
std::transform(std::begin(fd_name), std::end(fd_name), std::begin(fd_name), ::tolower);
std::transform(std::begin(type_id), std::end(type_id), std::begin(type_id_lower), ::tolower);
I would not use such long identifiers like whole_string or starting_substring. It is clear enough from the parameter declaration that the lambda deals with strings. Too long names make the code less readable.
And there is no sense to use general functions std::begin and std::end. The lambda is written specially for strings.
Also you could use only one return statement.`For example
auto is_start_with = []( std::string const &source, std::string const &target )
{
return !( source.size() < target.size() ) &&
std::equal( target.begin(), target.end(), source.begin() );
}
Or even like
auto is_start_with = []( std::string const &source, std::string const &target )
{
return ( not ( source.size() < target.size() ) ) &&
std::equal( target.begin(), target.end(), source.begin() );
}

To find duplicate entry in c++ using 2D Vector (std::vector)

I wrote a program to find duplicate entry in a table. I am a beginner in C++, hence I don't know how this program is working efficient. Is there any other idea to write this program? Here I have 3 tables (2D Vector), that they are 1)aRecord_arr 2)mainTable and 3)idxTable. idxtable is use to identify the keys to check duplicate entry. aRecord_arr table to be add in maintable. If it is already exist in maintable, it will show the error "Duplicate Entry". So Check this program, and give your suggestions.
typedef vector<string> rec_t;
typedef vector<rec_t> tab_t;
typedef vector<int> cn_t;
int main()
{
tab_t aRecord_arr= { {"a","apple","fruit"},
{"b","banana","fruit"} };
tab_t mainTable = { {"o","orange","fruit"},
{"p","pineapple","fruit"},
{"b","banana","fruit"},
{"m","melon","fruit"},
{"a","apple","fruit"},
{"g","guava","fruit"} };
tab_t idxTable = { {"code","k"},
{"name","k"},
{"category","n"}};
size_t Num_aRecords = aRecord_arr.size();
int idxSize = idxTable.size();
int mainSize = mainTable.size();
rec_t r1;
rec_t r2;
tab_t t1,t2;
cn_t idx;
for(int i=0;i<idxSize;i++)
{
if(idxTable[i][1]=="k")
{
idx.push_back(i);
}
}
for(size_t j=0;j<Num_aRecords;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r1.push_back(aRecord_arr[j][idx[id]]);
}
t1.push_back(std::move(r1));
}
for(int j=0;j<mainSize;j++)
{
for(unsigned int id=0;id<idx.size();id++)
{
r2.push_back(mainTable[j][idx[id]]);
}
t2.push_back(std::move(r2));
}
for(size_t i=0;i<t1.size();i++)
{
for(size_t j=0;j<t2.size();j++)
{
if(t1[i]==t2[j])
{
cout<<"Duplicate Entry"<<endl;
exit(0);
}
}
}
}
If you want to avoid duplicate entries in an array, you should consider using a std::setinstead.
What you want is probably a std::map or a std::set
Don't reinvent the wheel, the STL is full of goodies.
You seem to be rooted in a weakly typed language - but C++ is strongly typed.
You will 'pay' the disadvantage of strong typing almost no matter what you do, but you almost painstakingly avoid the advantage.
Let me start with the field that always says 'fruit' - my suggestion is to make this an enum, like:
enum PlantType { fruit, veggie };
Second, you have a vector that always contain 3 strings, all with the same meaning. this seems to be a job for a struct, like:
struct Post {
PlantType kind;
char firstchar;
string name;
// possibly other characteristics
};
the 'firstchar' is probably premature optimization, but lets keep that for now.
Now you want to add a new Post, to an existing vector of Posts, like:
vector<Post> mainDB;
bool AddOne( const Post& p )
{
for( auto& pp : mainDB )
if( pp.name == p.name )
return false;
mainDB.push_back(p);
return true;
}
Now you can use it like:
if( ! AddOne( Post{ fruit, 'b', "banana" } ) )
cerr << "duplicate entry";
If you need speed (at the cost of memory), switch your mainDB to map, like:
map<string,Post> mainDB;
bool AddOne( const Post& p )
{
if( mainDB.find(p.name) != mainDB.end() )
return false;
mainDB[p.name]=p;
return true;
}
this also makes it easier (and faster) to find and use a specific post, like
cout << "the fruit is called " << mainDB["banana"].name ;
beware that the above will cause a runtime error if the post dont exists
As you can see, firstchar was never used, and could be omitted. std::map
has a hash-function-specialization for string keys, and it will probably be
orders of magnitude faster than anything you or I could whip up by hand.
All of the above assumed inclusion of the correct headers, and
using namespace std;
if you dont like using namespace, prepend std:: to all the right places
hope it helps :)

C++ storing functions and operators in a structure

How to improve a data structure for storing functions in arithmetic parser converting from infix to postfix notation?
At this moment I am using an array of char arrays:
char *funct[] = { "sin", "cos", "tan"... }
char text[] = "tan";
This impementation is a little bit confused and leads to the following comparisions, if we test char to be a function
if ( strcmp ( funct[0], text) == 0 ) || ( strcmp ( funct[1], "text ) == 0 ) || ( strcmp ( func[2], text) == 0 ))
{
... do something
}
( or to the for cycle version).
If there are a lot of functions (and a lot of comparisions), the index referencing leads to errors and it is not clear. There is also a necessity to change the index when we remove/add a new function....
How to improve such a structure so as it is easy to read, easy to maintain and easy to scale up?
I was thinking about enum
typedef enum
{
Fsin=0,
Fcos,
Ftan
} TFunctions;
which results to
if ( strcmp ( funct[Fsin], text) == 0 ) || ( strcmp ( funct[Fcos], "text ) == 0 ) || ( strcmp ( func[Ftan], text) == 0 ))
{
...
but there may be a better solution...
You can use std::map.
enum functions
{
sin,
cos,
tan
};
std::map<std::string, unsigned char> func_map;
func_map["sin"] = sin;
func_map["cos"] = cos;
func_map["tan"] = tan;
// then:
std::string text = "cos";
std::map<char*, unsigned char>::iterator it;
it = func_map.find(text);
if(it != func_map.end())
{
// ELEMENT FOUND
unsigned char func_id = it->second;
}
else
{
// NOT FOUND
}
For fastest code you may have some kind of map as follow:
typedef std::map<std::string, func_t> func_map;
func_map fm;
fm["sin"] = sin_func(); // get value of this entry from somewhere
fm["cos"] = cos_func(); // for example sin_func or cos_func
auto i = fm.find( "sin" );
if( i != fm.end() ) {
func_t f = i->second; // value found, we may use it.
}
Also if there is really a lot of items you may use std::unordered_map instead of std::map

C++ Integer [?]

In Java, strings have a charAt() function.
In C++, that function is simply stringname[INDEX]
However, what if I wanted to use a particular number at a certain index of an integer?
E.g.
int value = 9123;
Let's say I wanted to work with the index 0, which is just the 9.
Is there a way to use index at's with integers?
int value = 9123;
std::stringstream tmp;
tmp << value;
char digit = (tmp.str())[0];
No, there is no standard function to extract decimal digits from an integer.
In C++11, there is a function to convert to a string:
std::string string = std::to_string(value);
If you can't use C++11, then you could use a string stream:
std::ostringstream stream;
stream << value;
std::string string = stream.str();
or old-school C formatting:
char buffer[32]; // Make sure it's large enough
snprintf(buffer, sizeof buffer, "%d", value);
std::string string = buffer;
or if you just want one digit, you could extract it arithmetically:
int digits = 0;
for (int temp = value; temp != 0; temp /= 10) {
++digits;
}
// This could be replaced by "value /= std::pow(10, digits-index-1)"
// if you don't mind using floating-point arithmetic.
for (int i = digits-index-1; i > 0; --i) {
value /= 10;
}
int digit = value % 10;
Handling negative numbers in a sensible way is left as an exercise for the reader.
You can use the following formula (pseudo-code) :
currDigit = (absolute(value) / 10^index) modulo 10; // (where ^ is power-of)
Just to make things complete, you can also use boost::lexical_cast, for more info check out the documentation here.
Basically its just a nice wrapper around the code which can be found at Andreas Brinck answear.
Another solution, which does use 0 for the lestmost digit. digits is used to break down value into individual digits in written order. (i.e. "9347" becomes 9,3,4,7). We then discard the first index values. I.e. to get the 3nd digit, we discard the first two and take the new front.
if (value==0 && index ==0) return 0; // Special case.
if (value <0) { ... } // Unclear what to do with this.
std::list<char> digits;
while (value) {
digits.push_front(value % 10);
value /= 10;
}
for(; index > 0 && !digits.empty(); index--) {
digits.pop_front();
}
if (!digits.empty()) {
return digits.front();
} else
{
throw std::invalid_argument("Index too large");
}
An integer is not a string and therefor you can not do that. What you need is indeed to convert an integer to string. You can use itoa or have a look here.
Try sprintf to write the integer out to a string:
http://www.cplusplus.com/reference/clibrary/cstdio/sprintf/
Then you can index into the char array that you've just printed into.
I've implemented a variant of giorashc s solution, with all the suggested fixes and issues resolved: Its a bit long but it should be fast if everything is inlined: Most of the code is tests which I've left in for completeness.
#include <iostream>
#include <math.h>
char get_kth_digit( int v, int index)
{
assert(v>0);
int mask = pow(10,index);
return '0'+(v % (mask*10))/mask;
}
int count_digits( int v )
{
assert(v>0);
int c=0;
while(v>0)
{
++c;
v/=10;
}
return c;
}
char get_int_index(int v, int index)
{
if( v==0 ) return '0';
if( v < 0 )
{
if(index==0) { return '-'; }
return get_int_index(-v,index-1);
}
// get_kth_digit counts the wrong way, so we need to reverse the count
int digits = count_digits(v);
return get_kth_digit( v, digits-index-1);
}
template<typename X, typename Y>
void compare(const X & v1, const Y & v2, const char * v1t, const char * v2t, uint32_t line, const char * fname )
{
if(v1!=v2)
{
std::cerr<<fname<<":"<<line<<": Equality test failed "<< v1t << "("<<v1<<") <> " << v2t <<" ("<<v2<<")"<<std::endl;
}
}
#define test_eq(X,Y) compare(X,Y,#X,#Y,__LINE__,__FILE__)
int main()
{
test_eq( 1, count_digits(1) );
test_eq( 1, count_digits(9) );
test_eq( 2, count_digits(10) );
test_eq( 2, count_digits(99) );
test_eq( 3, count_digits(100) );
test_eq( 3, count_digits(999) );
test_eq( '1', get_kth_digit(123,2) );
test_eq( '2', get_kth_digit(123,1) );
test_eq( '3', get_kth_digit(123,0) );
test_eq( '0', get_kth_digit(10,0) );
test_eq( '1', get_kth_digit(10,1) );
test_eq( '1', get_int_index(123,0) );
test_eq( '2', get_int_index(123,1) );
test_eq( '3', get_int_index(123,2) );
test_eq( '-', get_int_index(-123,0) );
test_eq( '1', get_int_index(-123,1) );
test_eq( '2', get_int_index(-123,2) );
test_eq( '3', get_int_index(-123,3) );
}
Longer version respect to Andreas Brink.
The C++ library is designed so that between "sequences" and "values" there is a "mediator" named "stream", that actually act as a translator from the value to their respecting sequence.
"sequences" is an abstract concept whose concrete implementation are "strings" and "files".
"stream" is another abstract concept whose correspondent concrete implementation are "stringstream" and "fstream", that are implemented in term of helper classes "stringbuf" and "filebuf" (both derived form the abstract "streambuf") and from a helper object of "locale" class, containing some "facets".
The cited answer code, works this way:
The tmp object of class stringstream is default-constructed: this will construct also internally a stingbuf and a string, plus a locale referencing the facets of the system global locale (the default one remaps the "classic" or "C" locale)
The operator<< between stream and int function is called: there is one of them, for all the basic types
The "int version" gets the num_put facet from the locale, and a "buffer iterator" from the buffer, and calls the put function passing the format flags of the given stream.
the "put function" actually converts the number into the character sequence thus filling the buffer
When the buffer is full, or when a particular character is inserted or when the str function is called, the buffer content is "sent" (copyed, in this case) to the string, and the string content returned.
This very convoluted process looks complex at first but:
Can be completely hidden (resulting in two lines of code)
Cam be extended to virtually anything but...
It is often kept as a (sort of ) misery in its details in the most of C++ courses and tutorials
I would convert it to a string, then index it -- CPP also has the:
str.at(i)
function similar to Java's.
Another simpler loop in C++11 would be a range based loop --
int i = 0
for(auto s : int_or_str){
if(i == idx)
cout << s;
else
i++
}
I guess this isn't easier than the standard for loop -- thought auto may be helpful, not really. I know this is answered, but I prefer simple and familiar answers.
Zach

hashkey collision when removing C++

To make the search foreach "symbol" i want to remove from my hashTable, i have chosen to generate the hashkey i inserted it at. However, the problem that Im seeing in my remove function is when I need to remove a symbol from where a collision was found it previously results in my while loop condition testing false where i do not want.
bool hashmap::get(char const * const symbol, stock& s) const
{
int hash = this->hashStr( symbol );
while ( hashTable[hash].m_symbol != NULL )
{ // try to find a match for the stock associated with the symbol.
if ( strcmp( hashTable[hash].m_symbol , symbol ) == 0 )
{
s = &hashTable[hash];
return true;
}
++hash %= maxSize;
}
return false;
}
bool hashmap::put(const stock& s, int& usedIndex, int& hashIndex, int& symbolHash)
{
hashIndex = this->hashStr( s.m_symbol ); // Get remainder, Insert at that index.
symbolHash = (int&)s.m_symbol;
usedIndex = hashIndex;
while ( hashTable[hashIndex].m_symbol != NULL ) // collision found
{
++usedIndex %= maxSize; // if necessary wrap index around
if ( hashTable[usedIndex].m_symbol == NULL )
{
hashTable[usedIndex] = s;
return true;
}
else if ( strcmp( hashTable[usedIndex].m_symbol , s.m_symbol ) == 0 )
{
return false; // prevent duplicate entry
}
}
hashTable[hashIndex] = s; // insert if no collision
return true;
}
// What if I need to remove an index i generate?
bool hashmap::remove(char const * const symbol)
{
int hashVal = this->hashStr( symbol );
while ( hashTable[hashVal].m_symbol != NULL )
{
if ( strcmp( hashTable[hashVal].m_symbol, symbol ) == 0 )
{
stock temp = hashTable[hashVal]; // we cansave it
hashTable[hashVal].m_symbol = NULL;
return true;
}
++hashVal %= maxSize; // wrap around if needed
} // go to the next cell meaning their was a previous collision
return false;
}
int hashmap::hashStr(char const * const str)
{
size_t length = strlen( str );
int hash = 0;
for ( unsigned i = 0; i < length; i++ )
{
hash = 31 * hash + str[i];
}
return hash % maxSize;
}
What would I need to do to remove a "symbol" from my hashTable from a previous collision?
I am hoping it is not java's equation directly above.
It looks like you are implementing a hash table with open addressing, is that right? Deleting is a little tricky in that scheme. See http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf:
"Deletion of keys is problematic with open addressing: If there are two colliding keys x and y with h(x) = h(y), and key x is inserted before key y, and one wants to delete key x, this cannot simply be done by marking T[h(x)] as FREE, since then y would no longer be found. One possibility would be to mark T[h(x)] as DELETED (another special entry), which is skipped when searching for a key. A table place marked as DELETED may also be re-used for storing another key z that one wants to insert if one is sure that this key z is not already in the table (i.e., by reaching the end of the probe sequence for key z and not finding it). Such re-use complicates the insertion method. Moreover, places with DELETED keys fill the table."
What you need to do is create a dummy sentinel value that represents a "deleted" item. When you insert a new value into the table, you need to check to see if an element is NULL or "deleted". If a slot contains this sentinel "deleted" value or the slot is NULL, then the slot is a valid slot for insertion.
That said, if you are writing this code for production, you should consider using the boost::unordered_map, instead of rolling your own hash map implementation. If this is for schoolwork,... well, good luck.