I try to delete list element and always get error message.
Firstly I have this class structure :
Class X
{ public:
ID;
name;
}
then I have list container.
Now, I want to delete specific element from container.
void delete ( list<X> a , X b )
{
list<X>::iterator itr;
for ( itr =a.begin() ; itr != a.end() ; itr++ )
{
if ( *itr.ID == b.ID )
{ a.erase(itr) ; }
}
}
But, I get error:
" iterator doesn't have ID ".
How can I fix it?
This is because the dot operator . is "stronger" than the dereference operator *. According to this table, dot has a precedence of two, while dereference asterisk * has a precedence of three (lower is stronger). This means that without the parentheses the compiler tries to get iterator's member ID, and then dereference the value of ID. This is not possible, because the iterator has no member called ID.
You need to put parentheses to enforce the precedence that you want:
if ( (*itr).ID == b.ID )
Alternatively, you can use the -> operator to dereference the iterator:
if ( itr->ID == b.ID )
Note: C++ Standard Library provides a way to do this without a loop:
a.erase(
remove_if(
a.begin()
, a.end()
, [](X x){ return x.ID == b.ID; }
)
, a.end()
);
Demo on ideone.
i prefer to use itr->ID instead of *itr.ID. the later is a little confusing sometime.
Related
As stated in the title, I'm trying to find the index of an element in a vector of pairs. I have the following vector: std::vector<std::pair<std::string, double>> dict.
The content of my dict is:
Name1 11
Name2 9
Name3 10
Name4 12
Name5 13
All I have in order to find the index is the first attribute of the pair. For example I have Name5 and I would like to find 4. (Since Name5 is the fifth element).
Does anyone have an idea how to do it ?
I tried something but it doesn't seem to work:
auto it = std::find(dict.begin(), dict.end(), movieName);
where movieName is an std::string with "Name5" inside.
Thank you!
You can use a predicate to decide which entries in the vector should match. It's easiest to do that with a lambda:
auto it = std::find_if(dict.begin(), dict.end(),
[&](const auto& pair) { return pair.first == movieName; });
After you have the iterator, compare it to dict.end() to see if there was any match, and if there's a match you can convert it to an index into the vector using std::distance(), as d4rk4ng31 commented under the question.
I would simply go with a normal for_each loop.
So:
int index = 0;
for(const auto& pair : dict) {
if(pair.first == <whatever>) {
break;
}
index++;
}
//if index == dict.size() then print element not found
Other way would be using std::find_if() ( Thanks #Tony Delroy :) )
auto index = std::distance(dict.begin(), std::find_if(dict.begin(), dict.end(), [&](const auto& pair) { return pair.first == movieName; }));
Im having this issue with comparing pairs. I want use find() to my vector which contains pairs like this:
vector<pair<PersonID, Cost>> friendlist;
PersonID and Cost are both just regular ints. And the problem here is that I want to specifically use the find() just on the PersonID, I'm not interested on the Cost.
if(friendlist.begin(), friendlist.end(), std::make_pair(toid, Cost)) !=
friendlist.end() )
toid here is the id I want to look for within the vector. So what I should do with the other field that make_pair requires?
std::find_if(friendlist.begin(), friendlist.end(),
[=](const std::pair<PersonID, Cost>& elem) {
return elem.first == toid;
});
Example: I have a class of myClass which consists of 3 private attributes:
string itemName
float amount
string date
Then I create a list of myClass
list<myClass> mytemp;
In my mytemp I store a few items inside:
[ itemName ] [ amount ] [ date ]
myproductA 10 011214
myproductB 20 010115
myproductC 30 020115
myproductD 40 040115
I would like to delete myproductC
I currently have:
list<myClass>::iterator p=mytemp.begin();
//productC would be list(3)
p++; p++; p++;
//therefore remove:
mytemp.remove(p);
Am I right to say that?
However p is an iterator, but list::remove wants a value.
How do I overcome this problem?
If you are sure that the target element in the list is the third element then instead of this code
list<myClass>::iterator p=mytemp.begin();
//productC would be list(3)
p++; p++; p++;
//therefore remove:
mytemp.remove(p);
You can replace it with this, if you are using C++11 or later:
mytemp.erase( std::next( mytemp.begin(), 2 ) );
Or this if you are using an older version:
list<myClass>::iterator p = mytemp.begin();
std::advance( p, 2 );
mytemp.erase( p );
To use std::next() or std::advance(), you need #include <iterator>.
As for the method remove(), it removes all elements of the list that are equal to a given value.
Use std::list::erase() method.
I am doing a task that requires to calculate a metric from a linked list that contains multiple linked lists of char (each row is a single linked list as shown in the graph). So I will need to iterate through every node that contains a space from the second row, to check how many spaces are surrounding by four other spaces (top, bottom, left, right). For instance, referring to the graph below, the second space in the third row is surrounding by four spaces, so count++. (the "H" just simply means non-space character, sorry that I don't have enough reputation to post a real picture).
I am allowed to used the STL linked list library. I was trying to use three iterators to iterate through three rows at the same time. However, the code gets really messy and does not even work correctly as each row has different lengths. I have been thinking the solution for two days, but as I've been practicing C++ for only two months, so what I could think of is pretty limited. So I am wondering if anyone could give me a hint or a smarter solution, please.
space | space | --H -- | --H -- | -- H -- | NULL| NULL
--- H --| --H ---| space | space | --- H- | -- H -- | NULL
--- H --| space | space | space | -- H-- | space| NULL
space | --H -- | space | space | -- H -- | NULL | NULL
Following may help: (in C++11): Live example.
std::size_t countSpaceSurroundBySpace(const std::list<std::list<char>>& l)
{
if (l.size() < 3u) {
return 0u;
}
auto it1 = l.begin();
auto it2 = std::next(it1);
auto it3 = std::next(it2);
std::size_t count = 0u;
for (; it3 != l.end(); ++it1, ++it2, ++it3) {
// pointers on the 5 characters
std::list<char>::const_iterator its[5] = {
it1->begin(),
it2->begin(),
it2->begin(),
it2->begin(),
it3->begin()
};
if (its[0] == it1->end()) { continue; }
++its[0];
if (its[2] == it2->end()) { continue; }
++its[2];
++its[3];
if (its[3] == it2->end()) { continue; }
++its[3];
if (its[4] == it3->end()) { continue; }
++its[4];
for (; its[0] != it1->end() && its[3] != it2->end() && its[4] != it3->end();) {
if (std::all_of(std::begin(its), std::end(its), [](std::list<char>::const_iterator it) { return *it == ' '; })) {
++count;
}
for (auto& it : its) {
++it;
}
}
}
return count;
}
You can use a std::vector of std::list::iterators. You'd have an inner loop that just does whatever computation you want at each step, if the iterator isn't already at the corresponding list's end(). This will be a lot easier if your incoming lists are in turn provided as an array or a vector.
Is there a better way of appending a set to another set than iterating through each element ?
i have :
set<string> foo ;
set<string> bar ;
.....
for (set<string>::const_iterator p = foo.begin( );p != foo.end( ); ++p)
bar.insert(*p);
Is there a more efficient way to do this ?
You can insert a range:
bar.insert(foo.begin(), foo.end());
It is not a more efficient but less code.
bar.insert(foo.begin(), foo.end());
Or take the union which deals efficiently with duplicates. (if applicable)
set<string> baz ;
set_union(foo.begin(), foo.end(),
bar.begin(), bar.end(),
inserter(baz, baz.begin()));