In my Python code I have an issue that I need clarified before I start translating to c++: how to make proper dictionaries/lists that I can use the equivalent of "if var in _" in.
arbitrary example that needs translation:
CONFIRMATION = ('yes', 'yeah', 'yep', 'yesh', 'sure', 'yeppers', 'yup')
DECLINATION = ('no', 'nope', 'too bad', 'nothing')
varResponse = str(input('yes or no question'))
if varResponse in CONFIRMATION:
doSomething()
elif varResponse in DECLINATION:
doSomethingElse()
else:
doAnotherThing()
It's fairly easy to do similar tasks using arrays, like:
if (userDogName == name[0])
execute something;
but what I need is something like:
if (userDogName is one of a population of dog names in a dictionary)
execute something;
You can use the STL container class set. It uses balanced binary trees:
#include <iostream>
#include <set>
#include <string>
int main(int argc, char* argv[])
{
std::set<std::string> set;
std::set<std::string>::const_iterator iter;
set.insert("yes");
set.insert("yeah");
iter = set.find("yess");
if (iter != set.end( ))
{
std::cout << "Found:" << *iter;
}
else
{
std::cout << "Not found!";
}
return 0;
}
C++11 permits a solutions that's very similar to the Python code:
#include <iostream>
#include <set>
#include <string>
using namespace std;
set<string> CONFIRMATION = {"yes", "yeah", "yep", "yesh", "sure", "yeppers", "yup"};
set<string> DECLINATION = {"no", "nope", "too bad", "nothing"};
int main() {
cout << "yes or no question";
string varResponse;
getline(cin, varResponse);
if (CONFIRMATION.find(varResponse) != CONFIRMATION.end()) {
doSomething();
} else if (DECLINATION.find(varResponse) != DECLINATION.end()) {
doSomethingElse();
} else {
doAnotherThing();
}
}
Well, C++ isn't well suited for small throw-off programs, because it doesn't provide much infra-structure. You're meant to create your own infra-structure (such as, well, even just plain sets!) on top of the standard library. Or use some 3rd-party libraries, i.e. your choice.
So while Python comes with batteries included, with C++ there is no strong pressure to accept the particular provided batteries (because there are none), but you have to at least choose batteries.
For just the basic code, the Python snippet
CONFIRMATIONS = ("yes", "yeah", "yep", "yesh", "sure", "yeppers", "yup")
DECLINATIONS = ("no", "nope", "too bad", "nothing")
response = raw_input( "yes or no? " )
if response in CONFIRMATIONS:
pass # doSomething()
elif response in DECLINATIONS:
pass # doSomethingElse()
else:
pass #doAnotherThing()
can look like this in C++:
typedef Set< wstring > Strings;
Strings const confirmations = temp( Strings() )
<< L"yes" << L"yeah" << L"yep" << L"yesh" << L"sure" << L"yeppers" << L"yup";
Strings const declinations = temp( Strings() )
<< L"no" << L"nope" << L"too bad" << L"nothing";
wstring const response = lineFromUser( L"yes or no? " );
if( isIn( confirmations, response ) )
{
// doSomething()
}
else if( isIn( declinations, response ) )
{
// doSomethingElse()
}
else
{
// doAnotherThing()
}
But then, it relies on some infra-structure having been defined, like the Set class:
template< class TpElem >
class Set
{
public:
typedef TpElem Elem;
private:
set<Elem> elems_;
public:
Set& add( Elem const& e )
{
elems_.insert( e );
return *this;
}
friend Set& operator<<( Set& s, Elem const& e )
{
return s.add( e );
}
bool contains( Elem const& e ) const
{
return (elems_.find( e ) != elems_.end());
}
};
template< class Elem >
bool isIn( Set< Elem > const& s, Elem const& e )
{
return s.contains( e );
}
I used an operator<< because still as of 2012 Visual C++ does not support C++11 curly braces list initialization.
Here set is std::set from the standard library.
And, hm, the temp thingy:
template< class T >
T& temp( T&& o ) { return o; }
And, more infra-structure, the lineFromUser function:
wstring lineFromUser( wstring const& prompt )
{
wcout << prompt;
wstring result;
getline( wcin, result )
|| throwX( "lineFromUser: std::getline failed" );
return result;
}
Which, relies on a throwX function:
bool throwX( string const& s ) { throw runtime_error( s ); }
But that's about all, except that you have to put the C++ code I showed first, into some function, say, call that cppMain, and invoke that from your main function (even more infra-structure to define!):
int main()
{
try
{
cppMain();
return EXIT_SUCCESS;
}
catch( exception const& x )
{
wcerr << "!" << x.what() << endl;
}
return EXIT_FAILURE;
}
So, to do things even half-way properly in C++, there is some steep overhead.
C++ is mainly for larger programs, and Python (which I often use) for smallish programs.
And yes, I know that some students may or will react to that statement, either they feel that it's a slur on C++ to say that it's no good for small programs (hey, I make those all the time!) and/or it's a slur on Python to say that it's no good for large systems (hey, haven't you heard of YouTube, you dumb incompetent person?), but, that's the way that it is. Sometimes it can be more convenient to use the hammer one has to fasten a screw, so sometimes I, for example, use C++ to do some small task. But generally that's because it would be too much hassle to install Python on the machine at hand, and in general, to do a task X, it's best to use tools that have been designed for X-like work.
This can be solved using std::find on any Standard Template Library container.
std::vector<std::string> answers;
std::string input;
...
if(std::find(answers.begin(), answers.end(), input) != answers.end()) {
/* input was found in answers */
} else {
/* input was not found in answers */
}
For larger lists, it may be better to store your lists in a std::set object instead, as Tilo suggested. std::find will work the same.
Related
I am writing an app to parse lines in a text file. The problem is that I need to be able to load different routines depending on a variable set at run-time. I can not change the format of the incoming file.
int intFormat = 1; //Loaded from INI file
void __fastcall TForm1::Button1Click(TObject *Sender) {
myFileConverstion *myFC;
switch(intFormat) {
case 1:
myFC = new FileConverstionCompanyA();
case 2:
myFC = new FileConverstionCompanyB();
}
myFileConverstion->Execute("fileName");
}
Within ->Execute(), I would be calling private (or protected) methods to do the parsing. There are some of the methods that could be used across all formats, too.
What would be the best OOP way to do this?
Create a virtual object i.e: myFileConverstion? Then inherit from that for the CompanyA, B, C, etc.
write myFileConverstion with all the common methods (private/protected) and a virtual Execute(). Then just change the Execute() internals for the various "companies"?
I'm looking for some guidance.
Haven't really tried anything yet, I'm in the planning stage.
There would also be the possibility to realize the whole thing with std:.function by inserting them into some kind of lookup map. Here is some example:
#include <functional>
#include <iostream>
#include <unordered_map>
class FileConverter
{
using convert_engine_t = std::function< bool( const std::string& ) >;
std::unordered_map< size_t, convert_engine_t > engines;
convert_engine_t *activeEngine { nullptr };
public:
template < class T >
auto addEngine( size_t id, T && routine ) -> void
{
engines.emplace( id, std::forward< T >( routine ) );
}
auto setActiveEngine( size_t id ) -> bool
{
const auto iterFound = engines.find( id );
if ( iterFound == engines.end() )
return false;
activeEngine = &iterFound->second;
return true;
}
auto convert( const std::string fileName ) -> bool
{
if ( !activeEngine || !( *activeEngine ) )
return false;
return ( *activeEngine )( fileName );
}
};
int main()
{
struct MyConvertingEngineA
{
auto operator()( const auto& fn ) {
std::cout << "Doing A" << std::endl; return true;
}
};
auto myConvertingEngineB = []( const auto& fn ) {
std::cout << "Doing B" << std::endl; return true;
};
FileConverter myFC;
myFC.addEngine( 1, MyConvertingEngineA() );
myFC.addEngine( 2, std::move( myConvertingEngineB ) );
myFC.addEngine( 8, []( const auto& fn ){ std::cout << "Doing C" << std::endl; return true; } );
myFC.setActiveEngine( 1 );
myFC.convert( "MyFileA1" );
myFC.convert( "MyFileA2" );
myFC.setActiveEngine( 2 );
myFC.convert( "MyFileB" );
myFC.setActiveEngine( 8 );
myFC.convert( "MyFileC" );
myFC.setActiveEngine( 7 ); // Will fail, old engine will remain active
return 0;
}
Output:
Doing A
Doing A
Doing B
Doing C
A few explanations about the code:
The addEngine function uses templates with a forwarding reference and
perfect forwarding to provide the widest possible interface.
Engines are copied or moved here, depending on the type of reference passing. The engines are passed in form of "callable objects".
Different types like functors or lambdas can be added.
Even (as in the example) generic lambdas can be passed (auto parameter) as long as the function signature of of std::function is fulfilled.
This saves another redundant specification of the string type.
If you have large and complex engines, use a separate class instead of a lambda to keep the local scope small
Shared parser-functionality could also be passed to the respective engines via smart pointer if you don't want to have any inheritance.
class EngineA
{
std::shared_ptr< ParserCore > parserCore;
public:
EngineA( std::shared_ptr< ParserCore > parserCoreParam ) :
parserCore( std::move( parserCoreParam ) )
{}
auto operator()( const auto& fn ) {
std::cout << "Doing A" << std::endl; return true;
// -> parserCore->helperFuncForABC() ....;
}
};
I was wondering if there is an easy way to write this if statement in c++.
string c="B";
if(c=="B"||c=="X"||c=="I")
{
//stuff
}
for example,
string c="B";
if(c in {"b","X","I"})
{
//stuff
}
You can use the std:: find function to search your array.Suppose your array is arr=["C","X","I"] :
tofind string c="C"
For example your statement will change to:-
if(find(arr.begin(),arr.end(),c)!=arr.end())
{
//found do something
}
There is no "in" in C++
There is no direct support in language for this, but you can emulate it using function. For example, let us define a function that accept a string and a vector of strings to be compared:
bool in(const std::string& s, std::vector<std::string> v)
{
for (auto&& i : v)
if ( s == i)
return true;
return false;
}
now you can use this function directly in you if statement, using an initilizer list:
int main()
{
std::string c = "B";
if ( in(c, {"C","X","I", "B"}) )
std::cout << "found\n";
else
std::cout << "not found\n";
}
If doing multiple searches, std::set or std::unordered_map (C++11 hash table) will be better performance-wise than linear search through an array with std::find.
std::set<std::string> data_set{"B","X","I"};
//...somewhere else
bool has_c = data_set.count(c)>0;
Both std::set and std::unordered_maphave a count function that makes testing for a value pretty clean looking, i.e. avoiding iterators.
Program
Here's a full working program,
#include <string>
#include <set>
#include <iostream>
using namespace std;
int main()
{
set<string> data_set{"C","X","I"}
//...somewhere else
string c="B";
if( data_set.count(c)>0 )
{
cout << "here\n";
}
else
{
cout << "not\n";
}
}
Don't forget to set C++11 standard when you compile, e.g. g++ -std=c++11 main.cc.
I need a way to assign numbers to letters in C++, for example, '$' would represent the number 1. I obviously need to be able to obtain the number from the character with something like a function, e.g. getNumFromChar('$') would return 1 and getNumFromChar('#') would return 2. Is there an easy and fast way to do this in C++?
The fastest way is to write a 256 entry lookup table, containing the mapped values in the character's ASCII index. This is similar to how isdigit and tolower work, for example:
int getNumFromChar(char c)
{
static const int table[256] = {/* table entries */};
return table[c & 0xff];
}
If you would like to assign the values yourself use a map and store your key to letter combinations. If you are ok with preassigned unique values mapped to each letter, and are only using ASCII characters, then type cast them to integers... ex) std::static_cast< int >('$');
Create a vector std::vector<int> v(256,0); which is indexed by your characters and initially all of their numbers are zeros that you could treat as invalid numbers. Finally assign for each 'numbered' character some number e.g. v['$'] = 1; v['#'] = 2; using a fact that characters are actually integers from 0 to 255.
As pointed out in the comments, you can use a std::map in the following way:
#include <iostream>
#include <map>
#include <cstring>
struct myComp
{
bool operator()(const char* s1, const char* s2) const
{
return strcmp(s1, s2) < 0;
}
};
int main()
{
std::map<const char*, int, myComp> test;
test["$"] = 1;
test["#"] = 2;
std::cout << "$ -> " << test["$"] <<"\n";
std::cout << "# -> " << test["#"] <<"\n";
return 0;
}
Live demo here.
Majority of the other answers will work only if you have a maximum of 256 values to be stored. However, using Maps, you can store just any number of elements.
A lot of people are suggesting std::map<char,int>, which is fine and works, but a faster (?) way of doing this with no dependencies is to just use a massive switch statement
int getNumFromChar(char c){
switch(c){
case '$':
return 1;
case '#':
return 2;
//etc
}
return -1; //just in case of error, for style points
}
Depending on how much you care about performance/memory usage and how many case statements you'd have to write, this may or may not be a viable way to do what you want. Just thought I'd throw it out there since at the time of this writing I don't believe anyone has.
EDIT: Also, depending on the frequency of use of each individual character, and if you know the entire mapping before using this function or if you ever change the mapping, a std::map is way better, but I believe this is faster otherwise.
You could do something like this:
#include <map>
#include <iostream>
#include <exception>
typedef std::map<char, int> easymap_type;
class EasyMap {
public:
EasyMap() {}
virtual ~EasyMap() {}
void assign_int_to_char(const int& i, const char& c)
{
_map[c] = i;
}
int get_int_from_char(const char& c) const
{
easymap_type::const_iterator it = _map.find(c);
if (it == _map.end())
{
std::cerr << "EasyMap Error: uninitialized key - '" << c << "'" << std::endl;
throw std::exception();
}
return it->second;
}
private:
easymap_type _map;
};
int main()
{
EasyMap ezmap;
ezmap.assign_int_to_char(42, 'a');
std::cout << "EasyMap[a] = " << ezmap.get_int_from_char('a') << std::endl;
std::cout << "EasyMap[b] = " << ezmap.get_int_from_char('b') << std::endl;
return 0;
}
I handled an uninitizialized key by throwing an exception, but you could do it different ways.
If your compiler support c++11 feature,you can use std::unordered_map as container to store char and double like std::unordered_map<char,double>.
Unordered map is an associative container that contains key-value pairs with unique keys. Search, insertion, and removal of elements have average constant-time complexity.In your problem char is the key and double is your value,char-double must be the key-value stored in container.
There are already a lot of reasonable answers... I prefer the static_cast<int>('#')
And there always has to be the most stupid useless compile time template idea about how to solve a problem.
I know it's stupid, and I'm not good at this kind of things, but here is my shot at it in c++11. Don't take me seriously. I just had to do something dumb.
#include <string>
#include <array>
#include <utility>
#include <iostream>
constexpr uint kNbChars {3};
constexpr std::array<std::pair<char, int>, kNbChars> kCharToInt {
std::make_pair('$', 1)
, std::make_pair('#', 2)
, std::make_pair('#', 3)
};
template <char c>
int getInt()
{
for (auto pair : kCharToInt)
{
if (pair.first == c)
{ return pair.second; }
}
return -1;
}
int main()
{
std::cout << getInt<'#'>() << std::endl;
std::cout << getInt<'g'>() << std::endl;
}
I think you can make getInt() constexpr too in c++14, but I may be wrong and cannot check it right now.
Of course it really is useless since you have to know the letter at compile time, but you could work around that by, well, just not making getInt a template function...
I have a list of sites, e.g. site1, site2, site3, etc (a rather long one at that) that are mapped to a pair of single-digit integers that my program receives from it's remote client, and I need an efficient way to return (as a string) the site name based on this pair of integers. The first digit is significant by itself, and the second digit is not significant unless paired with the first. These "site codes" should each return a unique string.
Here's how I'm doing it currently:
#include<string>
#include<iostream>
#include<vector>
// sbits is a vector of integers from which these two integers are being pulled
std::string readSite( vector<int> sbits ) {
int rgcode = sbits[5];
int uid = sbits[6];
if ( rgcode == 0 ) {
if ( uid == 0 ) {
return "site1";
}
else if ( uid == 1 ) {
return "site2";
}
else if ( uid == 2 ) {
return "site3";
}
// throw an exception if it's not here
else {
std::throw 10;
}
}
else if ( rgcode == 1 ) {
if ( uid == 0 ) {
return "site4";
else if ( uid == 1 ) {
return "site5";
else {
std::throw 10;
}
}
else {
std::throw 5;
}
std::catch( int err ) {
std::cout << "An exception has occurred. Error "<< err << " closing." << std::endl;
exit;
}
}
Everything about this makes me die a little inside. It's tiresome to write, tiresome to read, and probably sub-optimal for what I need to do.
So my question is this: Is there a more elegant (and less suicide-inducing) way to do this?
I've been reading about std::enum, std::map, but they don't seem to fit what I'm trying to do here.
edit: Is there a way to do this using an ordered list of some sort for the sites? Something so I don't have to go through and write 70+ variations of the same line. Some way to iterate through each? Maybe?
You need to define data structure properly to simply your code:
typedef std::pair<int, int> RgCodeUidPair;
// rgcode, uid
Then you can search through cachedData map by using (rgcode, uid) as pair.
std::string readSite( int rgcode, int uid)
{
static std::map<RgCodeUidPair, std::string> cachedData; // cache data, only load once
if (cachedData.empty())
{
cachedData.insert(make_pair(make_pair(0, 0), "site1"));
cachedData.insert(make_pair(make_pair(0, 1), "site2"));
cachedData.insert(make_pair(make_pair(1, 0), "site3"));
cachedData.insert(make_pair(make_pair(1, 1), "site4"));
}
auto it = cachedData.find(make_pair(rgcode, uid));
if (it != cachedData.end())
{
return it->second;
}
// throw if not found
}
Another way of looking at things:
#include <array>
#include <vector>
std::string const& readSite(std::vector<int> const& sbits ) {
static std::array<std::array<std::string, 10>, 10> const strs{{
{{ "site1", "site2", "site3" }},
{{ "site4", "site5" }}
}};
return strs.at(sbits.at(5)).at(sbits.at(6));
}
A few points
Needs error handling for empty strings (can be handled upstream if necessary)
Note how the vector is passed by reference
Throw an actual exception class instead of an int.
A rather simple way is to reduce the pair of int to a unique string and then use to store the sites.
#include <iostream>
#include <string>
#include <map>
#include <sstream>
using namespace std;
typedef map <string, string> SiteMap;
typedef pair<int, int> IntPair;
SiteMap map;
string ConvertPairToStr (IntPair const& pair)
{
int first = pair.first;
int second = pair.second;
stringstream unq;
unq << first;
unq << "_";
unq << second;
return unq.str();
}
void StoreSite (string site, IntPair p)
{
string unq = ConvertPairToStr(p);
map [p] = site;
}
string GetSite (IntPair p)
{
string unq = ConvertPairToStr(p);
// Assuming site is already stored
return map[p];
}
I was wondering recently what the requirements were for range based for loops in c++11, as I had only ever seen examples of intended usage:
for (auto person : people)
{
cout << person.name << endl;
}
But given that a container need only have begin and end methods, but need not contain anything at all, would the below be considered 'bad practice' in any way? If nothing else, it is a fresh answer if someone asks you for a Fibonacci sequence in an interview!
#include <string>
#include <iostream>
#include <Windows.h>
using namespace std;
struct FibItr
{
FibItr(int cur = 1, int prev = 0) : mCur(cur), mPrev(prev) {}
FibItr & operator++()
{
mCur += mPrev;
mPrev = mCur - mPrev;
return *this;
}
int operator*(){ return mCur; }
bool operator!=(const FibItr & _rhs)
{
return mCur != _rhs.mCur || mPrev != _rhs.mPrev;
}
unsigned int mCur, mPrev;
};
struct Fib
{
FibItr begin() { return FibItr(); }
FibItr end() { return FibItr(0, 0); }
};
int main( int argc, char* argv[] )
{
for (auto num : Fib())
{
cout << num << endl;
Sleep(500);
}
return 0;
}
The question is not really about the auto for-loop but if it is reasonable to implement stranger kind of iterators. While there are corner-cases you can make a perfect good argument for implementing some operations as iterators (memoized fibonacci being a good example).
There are whole libraries devoted to turning iterators in something more, so some other people also think it is a good idea.
As an aside: Implementing an iterator is tricky business, which is why methods like this should be used with care. Boost.Iterator is a good set of helpers that can make that easier.