C++ find in vector - c++

I am trying to do function that would return postition where occurrence was found in vector. But my return value is always 0 and I'm sure that there is a match.
Here is the code:
int findInItemvector(vector<Item> vec, string name)
{
for(vector<Item>::iterator it = vec.begin(); it < vec.end(); it++)
{
if(it->getName() == name)
{
return it - vec.begin();
break;
}
else
{
return 0;
}
}
}

When your first element does not match, the else branch executes return, which leaves the function and rest of your loop is not executed. You want something like:
int findInItemvector(vector<Item> vec, string name)
{
for(vector<Item>::iterator it = vec.begin(); it < vec.end(); it++)
{
if(it->getName() == name)
{
return it - vec.begin();
}
}
return 0;
}
However, since first item can also be match (in which case it - vec.begin() == 0), I suggest you to use other guard value, such as -1 (which can never be valid vector index).

Your 'else' clause is the problem: if the first item isn't a match, the 'else' kicks in, and your 'return 0' statement breaks you out of the 'for' loop without trying any of the other elements in the vector.
Try getting rid of the 'else', and moving the 'return 0' to after the end of the 'for' loop.

Your function will always return 0 because of the way it's currently written. If a match is found in the first item of the vector the result of the subtraction is, of course, zero. If it doesn't match the else part executes and returns 0, and the function exits.
The function should probably look like this
int findInItemvector(const vector<Item>& vec, string name)
{
for(vector<Item>::const_iterator it = vec.begin(); it < vec.end(); it++)
{
if(it->getName() == name)
{
return it - vec.begin();
}
}
return -1;
}
Notice that I'm passing the vector by constant reference instead of by value, this will prevent an unnecessary copy of the vector from being made when this function is called.
Also, you should indicate failure using -1, not 0, since the latter is a legitimate result if the string you're looking for is in the first element of the vector.

Related

referencing an object using auto iterator

unordered_map<char,int> letter;
for (auto it = letter.begin(); it != letter.end() ; it++) {
if (it->second) return false;
}
for (auto it : letter) {
if (it.second) return false;
}
Above, there are 2 iterator loops which I believe output the same thing. I can understand that the it in the first loop points to the object in the unordered_map, so the second variable must be referenced with ->. But I dont understand how the second loop can do .second. Can anyone explain how to 2nd loop works?
The second loop is a range-based for loop. It is not returning an iterator, but is instead returning a copy of the key-value pair (pair<char, int>), so it does not need to ues a -> operator to access the values.
Your range-based for would be equivalent to this, only less verbose, of course.
for (auto it = letter.begin(); it != letter.end() ; it++) {
auto kvp = *it;
if (kvp.second) return false;
}

Removing from std::list while iterating

I have the following code:
bool resetTypeBit = true;
for (auto it = eventsList.begin(); it != eventsList.end(); ++it) {
CreatureEvent* curEvent = *it;
if (curEvent == event) {
it = eventsList.erase(it);
} else if (curEvent->getEventType() == type) {
resetTypeBit = false;
}
}
So I have the following scenario: eventList contains 01 item, and then, as soon as the for statement goes through for the first time and meet the it = eventsList.erase(it); line, the it variable becomes invalid, causing a segmentation fault on the next iteration of the for statement.
Any clues of what could be causing the problem?
If the item you remove is the last item in the list, the erase method will return end(). Your for loop will then try to increment that iterator, which results in undefined behaviour.
Another problem which you haven't come across yet is that, if the item you remove isn't the last item in the list, you'll end up skipping over the following item (because the iterator is incremented past the one that erase returns). You can think of erase as an increment operation that just happens to erase the item first.
The solution is to refactor the loop slightly, to move the increment to the end (and only if erase wasn't called):
bool resetTypeBit = true;
for (auto it = eventsList.begin(); it != eventsList.end(); ) {
CreatureEvent* curEvent = *it;
if (curEvent == event) {
it = eventsList.erase(it);
}
else {
if (curEvent->getEventType() == type) {
resetTypeBit = false;
}
++it; // move the increment to here
}
}
As it is written now, you are incrementing the iterator even in the erase branch, which means that you are always skipping the element just after an erased one. This is both incorrect and results in serious problems if the last element happens to be one to delete. To fix, you have to not increment if you already fix it by setting it to the element following the deleted one.
bool resetTypeBit = true;
for (auto it = eventsList.begin(); it != eventsList.end(); ) {
CreatureEvent* curEvent = *it;
if (curEvent == event) {
it = eventsList.erase(it);
continue;
} else if (curEvent->getEventType() == type) {
resetTypeBit = false;
}
++it;
}

How to jump to the end of a for loop, but not leaving it, with goto

I have a function that finds all multiple elements in a vector. If I send in {1,2,3,4,5,1,2,3,3,7} it returns {1,2,3}.
My input vector has about 100 to 10000 elements but I expect to have only very few different(!) duplicates; around 1-5%.
Hence I check against my duplicates vector if I already identified an element as occurring multiple times. If so, the function shall go on to the next element if there are any. For this I use a goto.
But I need to have a command after the goto label. Else the compiler complains. Is there any way to avoid the this and keep the goto? I know that I could use some other method, e.g. setting a bool accordingly and using a if(). However I think the goto method is straight forward.
vector<int> findDublicates(vector<int> const& v) {
// e.g. {1,2,3,4,5,1,2,3,7} -> {1,2,3}
vector<int> dublicates;
for (auto it(v.begin()); it != v.end() - 1;
++it) { // go through each element except the last
for (auto const& i :
dublicates) { // check if this is already a known dublicate
if (i == *it)
goto nextElement; // if so, goto the next element in v
}
for (auto it2(it + 1); it2 != v.end();
++it2) { // else compare it with the "not checked" elements in v
if (*it == *it2) { // if a dublicate is found, keep it
dublicates.emplace_back(*it);
break; // check the next element in v; could also use goto
// nextElement
}
}
nextElement:
cout << " "; // if I remove cout it won't compile: "expected
// primary-expression before '}' token"
}
return dublicates;
}
You should be able to use a semicolon as a no-op.
nextElement:
;
}
However, I'm not sure if your method for finding duplicates is efficient. You might be better off sorting the array, then iterating it once. Sorting the vector will group all of the duplicates together. Then you'll simply have to check if the current element is the same as the previous element.
If removing the goto won't kill you, try using a Boolean helper variable:
for(auto it(v.begin()); it!=v.end()-1; ++it) { //go through each element except the last
bool found = false;
for(auto const &i : dublicates) { //check if this is already a known dublicate
if(i==*it)
{
found = true;
break;
}
}
if (!found)
{
for(auto it2(it+1); it2!=v.end(); ++it2) { //else compare it with the "not checked" elements in v
if(*it==*it2) { //if a dublicate is found, keep it
dublicates.emplace_back(*it);
break; //check the next element in v; could also use goto nextElement
}
}
}
cout<<" "; //if I remove cout it won't compile: "expected primary-expression before '}' token"
}
Usage of goto is considered bad form in programming. Search the web for "spaghetti code goto".
I'd recommend restructuring your code to not use a goto. Gotos can be useful, but they are frowned upon and can usually be replaced with more readable structure.
Consider:
bool isDublicate( int candidate, vector<int> const & dublicates )
{
for ( auto const &i: dublicates )
if ( i == candidate ) return true;
return false;
}
vector<int> findDublicates(vector<int> const &v) {
//e.g. {1,2,3,4,5,1,2,3,7} -> {1,2,3}
vector<int> dublicates;
for(auto it(v.begin()); it!=v.end()-1; ++it) { //go through each element except the last
if ( isDublicate( *it, dublicates ) )
continue;
for(auto it2(it+1); it2!=v.end(); ++it2) { //else compare it with the "not checked" elements in v
if(*it==*it2) { //if a dublicate is found, keep it
dublicates.emplace_back(*it);
break; //check the next element in v; could also use goto nextElement
}
}
}
return dublicates;
}

c++:Searching in a vector

I'm trying to create a pricing system for computers and I want to create two vectors, one stores item names, and the other one, prices for the item. My plan is to have two methods, "find_item",that finds the item name inside of a vector and returns its index, and "get_itemPrice", that takes the index from find_item and gets the price. My problem is coming up with a code that takes a string object inside of a vector and returns its index position.
You can simply use std::find. It will return an iterator to the first element equal to the one you are searching for, or to the end() if none is found. You can then use std::distance to get an index from that, if you really need it.
Like this:
vector<int> vect;
int i = 0;
for (vector<int>::iterator iter = vect.begin(); iter != vect.end(); ++iter)
{
if (*iter == vect)
break;
i++;
}
if (i == vect.size())
// not found
else
// i is your index
if you really would like to make an algorithm do it like this, but generally one should not try to beat those in the stl see the algorithm header
unsigned find_str( const vector<string>& vec, const string& key ){
unsigned count = 0;
vector<string>::const_iterator it;
for ( it = vec.begin() ; it < vec.end(); it++ ){
if( *it == key)
return count;
count++;
}
/*throw not found error here.*/
}

How to avoid "doesn't return a value on all code paths" warning without using a list iterator?

Say I have an object containing a value. I wish to get the index of object with a particular value from a list of objects. I use the below code to do it,
int MyClass::getIndex(list& somelist, int requiredValue)
{
for( i=0; i != somelist.count(); ++i)
{
if(somelist.at(i)->value() == requiredValue)
return i;
else
continue;
}
return -1;
}
How to avoid the "doesn't return a value on all code paths" warning without using an iterator?
You must return T from the function in any case. If the value possibly does not exists in the list you have options:
return default value (nullptr for pointer for example, -1 for integer possibly)
use boost::optional<T>
return end iterator:
std::list<int>::iterator find_something(std::list<int> &my_list)
{
for (auto it = my_list.begin(); it != my_list.end(); ++it)
{
if (cond)
{
return it;
}
}
return my_list.end();
}
Also
If you just want to find the iterator to some value, use std::find:
auto it = std::find(my_list.begin(), my_list.end(), my_value);
Finally
Don't use list if you need access by index. Use vector in that case
The answer to this question is the same as the answer to "What do you want to happen when the element is not found?".