String array to C++ function - c++

I want to check if a given name is inside an array of possible names. I wrote this small debugging function ( yeah... I know it always return true ) trying to understand why it does not work and why I get the below error.
Code
char[] people_names = ["Mario","Luigi"];
bool lookupTerm (string term, string possible_names[]){
for(const string &possible_name : possible_names)
cout << possible_name << endl;
return true;
}
Error
jdoodle.cpp: In function 'bool lookupTerm(std::__cxx11::string, std::__cxx11::string*)':
jdoodle.cpp:19:38: error: no matching function for call to 'begin(std::__cxx11::basic_string<char>*&)'
I know that it must be really obvious but according to what I have searched for, it should work. Can someone point me in the right direction?

The problem is that when you pass an array to a function, it decays to a pointer to its first element.
It doesn't matter if you attempt to declare the argument as an array, the compiler still translates it as a pointer. string possible_names[] is equal to string* possible_names when you declare arguments.
The simple solution is to use either std::vector or std::array depending on your needs and use-case.
Using std::vector your code would look something like this:
std::vector<std::string> people_names = { "Mario", "Luigi" };
bool lookupTerm(const std::string& term, const std::vector<std::string>& possible_names) {
for (const std::string &possible_name : possible_names)
{
if (possible_name == term)
return true;
}
return false;
}
One line using std::find:
bool lookupTerm(const std::string& term, const std::vector<std::string>& possible_names) {
return std::find(possible_names.begin(), possible_names.end(), term) != possible_names.end();
}
If performance becomes a problem you can increase the performance of this by using a sorted vector (using std::sort) and std::lower_bound:
//at one point:
std::sort(people_names.begin(), people_names.end());
bool lookupTerm(const std::string& term, const std::vector<std::string>& sorted_possible_names) {
//sorted_possible_names must be always sorted when you call this!
auto i = std::lower_bound(sorted_possible_names.begin(), sorted_possible_names.end(), term);
return (i != sorted_possible_names.end() && *i == term);
}

Related

How to sort vector of objects by a private string variable alphabetically

I cannot figure out how to sort a vector of objects by one of the member variables called VIN, which is of data type string. I am to either perform a bubble sort or a selection sort. I am most familiar with a bubble sort, so that's the direction I attempted to take. However, I am aware that I need to compare both of the strings by either making them all uppercase or lower case. Keep in mind, the strings also will have number characters in them as well.
So my question is:
1) How to I convert a string either all lowercase or all ASCII numbers and
2) What data type should the temp variable be (data type of the class or some other data type).
Here is the (incomplete) code I have so far:
void sortInventory(vector<Vehicle> &carList)
{
bool swap;
string temp;
do
{
swap = false;
for (int count = 0; count < carList.size(); count++)
{
if (carList[count].getVIN() > carList[count + 1].getVIN())
{
temp = carList[count].getVIN();
carList[count].getVIN() = carList[count + 1].getVIN();
carList[count + 1].getVIN() = temp;
swap = true;
}
}
} while (swap);
}
Here is my class declaration:
class Vehicle
{
private:
string VIN;
public:
string getVIN();
void setVIN(string);
};
Here is my class implementation:
string Vehicle::getVIN()
{ return VIN; }
void Vehicle::setVIN(string input)
{ VIN = input; }
Thanks!
You can do std::sort(carList.begin(),carList.end(),vehicleCompare) where vehicleCompare is a comparison function that you define. See sort documentation. Then, to uppercase you can use std::toupper, as shown in this guide.
std::string myToUpper(std::string in) {
std::transform(in.begin(), in.end(),in.begin(), ::toupper);
return in;
}
So the comparison operator(*) will be:
bool vehicleCompare (const Vehicle a, const Vehicle b) {
const std::string a_name = myToUpper(a.getVIN());
const std::string b_name = myToupper(b.getVIN());
return (a_name < b_name);
}
Useful reading about string comparison operator.
By the way, your string getVIN() method should be const, that is you should change its declaration to string getVIN() const.
If you want to keep your sorting function, the point is that in any case you'll have to define a proper comparison operator, as the one shown here.
To specifically answer to your second question, temp could be auto in C++11, or simply std::string. Then the way you are trying to assign your VIN value is wrong. Given the interface you have given, it should be:
auto temp = carList[count].getVIN();
carList[count].setVIN(carList[count + 1].getVIN() );
carList[count + 1].setVIN(temp);
Although it still might get nasty when you start to have more than one member variable to copy: you should instead build a copy constructor and change your code to:
auto temp = carList[count]; //you can use Vehicle instead of auto as type
carList[count] = carList[count + 1];
carList[count + 1] = temp;
The copy constructor will be:
Vehicle(const Vehicle& in)
: VIN(in.getVIN() )
{}
And, at that point, you'll also want a constructor from string, and an empty constructor.
Vehicle(std::string& inVIN)
: VIN(inVIN)
{}
Vehicle(const Vehicle& in)
{} //All input members get initialized through the default constructor.
(*) Note that this comparison method wouldn't be the most efficient, as it makes uppercase the whole string while the first few characters are normally sufficient to decide their order. So a more efficient way would be to uppercase one character at the time and compare it before deciding if to uppercase another character.
Answer to question 1: You can make a simple function that converts a std::string to upper.
void string_to_upper(string &s) {
for(int l = 0; l < s.length(); ++l) {
s[l] = toupper(s[l]);
}
}
First, your Vehicle::getVIN() method should be marked as const, to implement proper const-correctness:
string Vehicle::getVIN() const
{
return VIN;
}
Then, note that you don't need to reinvent the wheel and reimplement a sorting algorithm from scratch in production code in C++ (unless this is a learning exercise/homework about writing sorting code).
You can simply use the standard std::sort() algorithm implemented in the STL, and customize the comparison criteria using a convenient C++11 lambda, e.g.:
// std::vector<Vehicle> carList;
std::sort(carList.begin(), carList.end(),
[](const Vehicle& v1, const Vehicle& s2)
{
/* Code implementing custom Vehicle comparison */
}
);
Your code in the lambda could be something like this:
[](const Vehicle& v1, const Vehicle& s2)
{
// Use stricmp() to compare strings in a case insensitive way
return (stricmp(v1.getVIN().c_str(), v2.getVIN().c_str()) < 0);
}
Instead of calling stricmp(), you can use boost::to_upper(), or some other method among the ones showed e.g. in this thread on StackOverflow:
Case insensitive string comparison in C++

How to iterate through all elements of set C++

[UPDATE: My problem is solved! Lots of thanks to Mike Seymour and Niall and all you guys!]
My code has errors in the for loop and I do not know how to fix it :(
MyClass::ITECH7603Class(set<Student>* students) {
/* Initialize dynamically the group field */
group = new map<string, Student>();
for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
addStudent(it);
}
}
void MyClass::addStudent(Student* studentPtr) {
string fullName = studentPtr->getName() + " " + studentPtr->getSurname();
group->insert(pair<string, Student>(fullName, *studentPtr));
}
So the main idea is to loop through all students in the set, and add each student into a map group. Any help? Thank you very much!
for (set<Student>::iterator it = students->begin; it != students->end; it++) {
addStudent(it);
}
should be:
for (set<Student>::iterator it = students->begin(); it != students->end(); it++) {
//^^ //^^
addStudent(it);
}
addStudent takes a pointer, while it is an iterator, so can't be passed directly.
You should change addStudent to take either a value or a pointer/reference to const:
// option 1
void addStudent(Student);
addStudent(*it);
// option 2
void addStudent(Student const &);
addStudent(*it);
// option 3
void addStudent(Student const *);
addStudent(&*it);
If, as you say in a comment, you must leave it taking a mutable pointer, then you'll need some grotesquery to deal with the fact that elements of the set are immutable:
// nasty option
addStudent(const_cast<Student*>(&*it));
// slightly less nasty option
Student copy = *it;
addStudent(&copy);
Beware that the first option will give undefined behaviour if the function uses the dodgy pointer to make any modification to the Student object stored in the set. The second makes a temporary copy, which can be modified without breaking the set. This is fine as long as addStudent only stores a copy of the object passed to it, not the pointer itself, which will become invalid when copy is destroyed.
In c++11 you can use range for sytax:
for (const auto &student : *students)
{
addStudent(it);
}
Then change addStudent function signature to accept reference:
void MyClass::addStudent(const Student &student) {
While you've gotten answers that "fix" your code to the extent of compiling and producing results that you apparently find acceptable, I don't find them very satisfying in terms of code style. I would do this job rather differently. In particular, my code to do this wouldn't have a single (explicit) loop. If I needed to do approximately what you're asking for, I'd probably use code something like this:
std::pair<std::string, Student> make_mappable(Student &stud) {
return std::make_pair(stud.getName() + " " + stud.getSurName(), stud);
}
std::map<std::string, Student> gen_map(std::set<Student> const &input) {
std::map<std::string, Student> ret;
std::transform(input.begin(), input.end(),
std::inserter(ret, ret.end()),
make_mappable);
return ret;
}
There definitely would not be any new in sight, nor would there be any passing a pointer to a Student.
OTOH, since the data you're using as the key for your map is data that's already in the items in the set, it may more convenient all around to continue to use a set, and just specify a comparison function based on the student's name:
struct by_given_name {
bool operator()(Student const &a, Student const &b) const {
if (a.getName() < b.getName())
return true;
if (b.getName() < a.getName())
return false;
return a.getSurName() < b.getSurName();
}
};
std::set<Student, by_given_name> xform(std::set<Student> const &in) {
return std::set<Student, by_given_name>{in.begin(), in.end()};
}
For what its worth, a Live Demo of the latter.
Whether the latter is practical will typically depend on one other factor though: your ability to create a Student from only a name/surname. If you can't do that, searching by name will be inconvenient (at best), so you'd want to use a map.
I realize this probably isn't much (if any) help in completely what's apparently home-work for a class--but even if your class prevents you from actually turning in decent code, it seems worthwhile to me to at least try to learn to write decent code in addition to what it requires. If you do pass the class and get a job writing code, you'd probably rather your coworkers didn't want to hurt you.

Returning a pointer to a class within a class

this is the first time I've done something like this so I'm a little uncertain how I need to do this. I have a very simple class which contains some simple values and some getters:
class Nucleotide{
private:
char Base;
int Position;
int Polymorphic;
public:
Nucleotide(char ch, int pos);
int getPos();
char getBase();
int getPoly();
};
This class is present in another class that contains a vector of them:
class NucleotideSequence{
private:
std::string Name;
std::vector<Nucleotide> Sequence;
public:
NucleotideSequence(std::string name, std::vector<Nucleotide> seq);
std::string getName();
Nucleotide getBase(int pos1);
};
I want the method of the second class called getBase to be able to take a integer - say 1, and return the first Nucleotide object in the vector. What I've written is below:
Nucleotide NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++)
{
if(pos1 == (*i).getPos())
{
return i; // Return a pointer to the correct base.
}
}
}
I've got Nucleotide as the return type but I was wondering really how I should change this - since if I return nucleotide because of pass by value would it not just return a copy of the object at that place in the vector? So I'd rather return a pointer/reference. I'm using an iterator in the loop so should I just return a pointer with the value of the iterator? How do I do this? In the function I return i but should I be returning i&? I'm uncertain about the specifics - presumably if I'm returning a pointer my return type needs to be Nucleotide* or perhaps Nucleotide& since & means address of? I've thought this through and read Cpp tuts but I'm still slightly unsure of the right answer.
Thanks,
Ben.
You have to return the Nucleotide by reference:
Nucleotide & NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++)
{
if(pos1 == (*i).getPos())
{
return *i; // Notice the *i instead of i
}
}
}
A reference works very similarly to pointer (allows you to pass the actual object, not its copy), but cannot be null and cannot point to non-existing object, so it's a lot safer than pointer.
Note though, that if you don't find the desired Nucleotide, you don't return anything, what generally is not a good idea. In this case using pointers may actually be a better idea:
Nucleotide * NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); i++)
{
if(pos1 == (*i).getPos())
{
return &(*i);
}
}
return nullptr;
}
You don't return a pointer, you attempt to return the iterator. And the function is declared to return an instance and not a pointer. Also, if you don't find the Nucleotide you don't return anything at all leading to undefined behavior if you try to use the "returned" value.
You could change the function to return a pointer, or a reference, or just a by value (copying like it's declared like not.
You can also change so that the function takes the Nucleotide as an argument instead, and then return a boolean indicator if it was found or not.
bool NucleotideSequence::getBase(int pos1, Nucleotide& n)
{
for (...)
{
if (...)
{
n = *i;
return true;
}
}
return false; // Not found
}
As far as your question is concerned, returning a reference (&) as suggested by others is the solution.
In order to improve your code, I would as well suggest a change:
Either go for the operator[], or use the at() present in std::vector.
Thus, you can directly say:
return Sequence[pos1]; or return Sequence.at(pos1);
Your code will benefit from some use of references for efficiency's sake. The getBase method signature should look like this:
const Nucleotide& NucleotideSequence::getBase(int pos1)
The NucleotideSequence constructor signature should look like this:
NucleotideSequence(const std::string& name, const std::vector<Nucleotide>& seq);
And the getName method like this:
const std::string& getName();
(Although return value optimisation might make that less important.)
As for the contents of getBase, it might help understanding to break down the code into:
const Nucleotide* NucleotideSequence::getBase(int pos1)
{
for(std::vector<Nucleotide>::iterator i = Sequence.begin(); i != Sequence.end(); ++i)
{
Nucleotide& ref = *i; //Get a reference to the object this iterator points to
if(pos1 == ref.getPos()) //compare its base to the argument
{
return &ref; // Return a pointer to the correct object.
}
}
return NULL; //or null if we didn't find the object we wanted
}

How to use map::equal_range without a copy of the object?

I have a performance-sensitive function which uses a map<string, ...> to store some data.
I need to be able to look up values with any substring of some other string as the key, without creating an intermediate string (i.e., the goal is to prevent a heap allocation from happening merely because I want to look something up).
The obvious solution is to hold two separate data structures (perhaps with another map on the side, to map from some key to to each string) -- one for the strings, and one for references to those strings.
But I'm wondering, is there a better way to do this with just a map alone, or do I need another data structure? I'd like to avoid creating too many extra indirections if possible.
Sorry if I misunderstood, but would your problem be solved if you could use a "substring view" of the query string to search the multi-map, instead of an ordinary std::string object?
In that case something along the lines below would work (using C++11-based coding):
Define a substring-view object type. It is constructed from a string and (from,to) offsets, but does not make a copy of the substring:
class substrview
{
std::string::const_iterator _from;
std::string::const_iterator _to;
public:
substrview(
const std::string &s,
const std::size_t from,
const std::size_t to)
: _from(s.begin()+from), _to(s.begin()+to)
{ }
std::string::const_iterator begin() const
{ return _from; }
std::string::const_iterator end() const
{ return _to; }
};
In order to search the multi-map using the substring view, I suggest using the std::lower_bound and std::upper_bound methods from <algorithm>:
int main()
{
std::multimap<std::string,int> map {
{ "hello" , 1 },
{ "world" , 2 },
{ "foo" , 3 },
{ "foobar" , 4 },
{ "foo" , 5 },
};
std::string query { "barfoo" };
/* Search for all suffixes of "barfoo", one after the other: */
for (std::size_t i = 0 ; i < query.size() ; ++i) {
substrview subquery { query,i,query.size() };
auto found_from = std::lower_bound(begin(map),end(map),subquery,cmpL);
auto found_to = std::upper_bound(begin(map),end(map),subquery,cmpU);
/* Now [found_from,found_to) is the match range in the multi-map.
Printing the matches: */
while (found_from != found_to) {
std::cout << found_from->first << ", " << found_from->second << '\n';
++found_from;
}
}
}
For this to work, we only need to define the comparison operators cmpL and cmpU (one for lower_bound, the other for upper_bound – we need two because the comparison is assymetric: comparing a multi-map entry to a substringview in cmpL, and comparing a substringview to a multi-map entry in cmpU):
inline bool cmpL(
const std::pair<std::string,int> &entry,
const substrview &val)
{
return std::lexicographical_compare
(entry.first.begin(),entry.first.end(),val.begin(),val.end());
}
inline bool cmpU(
const substrview &val,
const std::pair<std::string,int> &entry)
{
return std::lexicographical_compare
(val.begin(),val.end(),entry.first.begin(),entry.first.end());
}
Working gist of the complete code: https://gist.github.com/4070189
You need a string_ref type which participates in the < relation with std::string. In the TS n3442, Jeffrey Yaskin proposes introducing a string_ref type influenced by Google's StringPiece and llvm's StringRef. If you can use either of those then you're pretty much done; otherwise writing your own to the proposed interface should be fairly easy, especially as you only need a subset of the functionality.
Note that if you have an implicit constructor from std::string:
string_ref(const std::string &s): begin(s.begin()), end(s.end()) {}
then the < relation with std::string comes for free.

Find array element by member value - what are "for" loop/std::map/Compare/for_each alternatives?

Example routine:
const Armature* SceneFile::findArmature(const Str& name){
for (int i = 0; i < (int)armatures.size(); i++)
if (name == armatures[i].name)
return &armatures[i];
return 0;
}
Routine's purpose is (obviously) to find a value within an array of elements, based on element's member variable, where comparing member variable with external "key" is search criteria.
One way to do it is to iterate through array in loop. Another is to use some kind of "map" class (std::map, some kind of vector sorted values + binarySearch, etc, etc). It is also possible to make a class for std::find or for std::for_each and use it to "wrap" the iteration loop.
What are other ways to do that?
I'm looking for alternative ways/techniques to extract the required element.
Ideally - I'm looking for a language construct, or a template "combo", or a programming pattern I don't know of that would collapse entire loop or entire function into one statement. Preferably using standard C++/STL features (no C++0x, until it becomes a new standard) AND without having to write additional helper classes (i.e. if helper classes exist, they should be generated from existing templates).
I.e. something like std::find where comparison is based on class member variable, and a variable is extracted using standard template function, or if variable (the one compared against "key"("name")) in example can be selected as parameter.
The purpose of the question is to discover/find language feature/programming technique I don't know yet. I suspect that there may be an applicable construct/tempalte/function/technique similar to for_each, and knowing this technique may be useful. Which is the main reason for asking.
Ideas?
If you have access to Boost or another tr1 implementation, you can use bind to do this:
const Armature * SceneFile::findArmature(const char * name) {
find_if(armatures.begin(), armatures.end(),
bind(_stricmp, name, bind(&string::c_str, bind(&Armature::name, _1))) == 0);
}
Caveat: I suspect many would admit that this is shorter, but claim it fails on the more elegant/simpler criteria.
Sure looks like a case for std::find_if -- as the predicate, you could use e.g. a suitable bind1st. I'm reluctant to say more as this smacks of homework a lot...;-).
Why 5 lines? Clean doesn't have a number attached to it. In fact, clean code might take more lines in the utility classes, which can then be reused over and over. Don't restrict yourself unnecessarily.
class by_name
{
public:
by_name(const std::string& pName) :
mName(pName)
{}
template <typename T>
bool operator()(const T& pX)
{
return pX.name == pName;
}
private:
std::string mName;
};
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
Within restriction:
class by_name { public: by_name(const std::string& pName) : mName(pName) {} template <typename T> bool operator()(const T& pX) { return pX.name == pName; } private: std::string mName; };
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
:)
C++0x has ranged-based for-loops, which I think would make the most elegant solution:
const Armature* SceneFile::findArmature(const std::string& pName) const
{
for (auto a : armatures)
{
if (a.name = pName) return &a;
}
return 0;
}
You would probably need to use STL map. It gives you possibility to get the element using keys. Your key would be the name of armature.
http://www.cplusplus.com/reference/stl/map/
EDIT: :D
one liner B-)
const Armature* SceneFile::findArmature(const Str& name){for (int i = 0; i < (int)armatures.size(); i++) if(name == armatures[i].name) return &armatures[i]; return 0;}
Holy shiz, you're using _stricmp? FAIL. Also, you didn't actually tell us the type of the vectors or any of the variables involved, so this is just guesswork.
const Armature* SceneFile::findArmature(const std::string& lols) {
for(auto it = armatures.begin(); it != armatures.end(); it++) {
if (boost::iequals(lols, (*it).name))
return &(*it);
return NULL;
}
Ultimately, if you need this, you should put the armatures or pointers to them in a std::map. A vector is the wrong container if you're searching into it, they're best for when the collection is what's important rather than any finding behaviour.
Edited to use a std::string reference.