test if a value is in a vector - c++

I have a class Board, with an operator==, and a class Graph, containing a Board* (let's call it tab) and a vector<Graph*> (children).
I have 2 vector<Graph*>, named opened and closed.
How can i look every children in an element of opened, and add a child to opened if this child is not already in closed?
Here is my attempt, but it doesn't compile.
for (vector<Graph*>::iterator itr = opened[0]->getchildren().begin(); itr != opened[0]->getchildren().end(); ++itr) {
// this doesn't compile
vector<Graph*>::iterator it = find(closed.begin(), closed.end(), *itr);
if(it != closed.end())
{
opened.push_back(*it);
}
}
I get:
no matching function for call to 'find(std::vector<Graph*>::iterator, std::vector<Graph*>::iterator, Graph*&)'
I don't really understand how std::find works. But I'm open to every method.

std::find returns an iterator, not a pointer to an iterator:
vector<Graph*>::iterator* it = NULL;
↑
// that line doesn't compile
it = find(closed.begin(), closed.end(), (*itr)->tab);
Your it is a pointer. You just want the actual iterator type:
vector<Graph*>::iterator it = find(...);
You check validity not by comparing against NULL but rather by comparing against the end iterator that you pass in:
if (it != closed.end())
{
...
}
Given the error you just provided, the issue is that find() is looking for a specific value by using operator==. You are looking for a Board* in a vector of Graph*. Those two are not comparable - you can only look for a Graph*. Unless you are looking for a Graph* that contains a Board*, in which case you would want to provide your own predicate via std::find_if

Concerning find, you have to check against the end iterator
it = find(closed.begin(), closed.end(), (*itr)->tab);
if (it != closed.end())
{
...

Other than the obvious error of comparing it against NULL instead of closed.end(), it seems that you want to look for a node of type Graph*.
std::find(start, finish, key) uses the iterators from first to last and invokes operator== on each element against 'key'. The 'things' stored in the vector and key have to be of the same type. Compiler is reporting they are not.
Key is of type Board*, while vector elements are Graph*.

I gave up on std::find and did two loops to compare opened and closed. Thanks for the help.

Related

How to tell if the directory_entry is the end of directory_iterator in C++

using std::filesystem, how can I tell that the directory_entry is the end of a directory_iterator?
here's an example of what I'm trying to do:
auto it = fs::directory_iterator(path);
for (const auto &i : it) {
if (i == it.back()) { // this works with `vector`s but not with `directory_iterator`
doSomethingWith(i); // call this function only on the last entry.
}
}
From docs -
If the directory_iterator reports an error or is advanced past the last directory entry, it becomes equal to the default-constructed iterator, also known as the end iterator. Two end iterators are always equal, dereferencing or incrementing the end iterator is undefined behavior.
However, the issue is incrementing directory_iterator invalidates all previous values.
So, one possible solution is to use the post-increment operation to find the last directory_entry.
auto it = fs::directory_iterator(path);
for (auto i = fs::begin(it); fs::begin(i) != fs::end(it); ) {
auto entry = *(i++);
if (fs::begin(i) == fs::end(it)) { // sugercoat of `i == fs::directory_iterator{}`
doSomethingWith(entry); // this is the last directory entry
} else {
doSomethingElse(entry); // non-last entry
}
}
You can use std::filesystem::end. See the docs here:
https://en.cppreference.com/w/cpp/filesystem/directory_iterator/begin
But in your example, you shouldn’t need to explicitly check as the loop will end correctly on its own.
A default constructed directory_iterator is the end iterator. See entry one in the constructor list: https://en.cppreference.com/w/cpp/filesystem/directory_iterator/directory_iterator

Efficiently remove last element from std::list

This seems like a simple problem, and it is certainly doable, but I'd like to do it efficiently.
The Objective:
Remove the last element from a std::list if it meets a condition.
The Problem:
My compiler (MSVC++ 10) is unhappy about casting a reverse iterator to a const iterator for a method call to std::list.erase(). The message is:
error C2664: 'std::_List_iterator<_Mylist>
std::list<_Ty>::erase(std::_List_const_iterator<_Mylist>)' : cannot
convert parameter 1 from 'std::reverse_iterator<_RanIt>' to
'std::_List_const_iterator<_Mylist>'
The Code I Tried:
std::list<mytype> mylist;
// lots of code omitted for clarity
bool ends_badly = true;
while(ends_badly && mylist.size() > 0)
{
auto pos = mylist.crbegin(); // Last element in the list
if ((*pos)->Type() == unwanted)
{
mylist.erase(pos); // Here is where the compiler complains
}
else
{
ends_badly = false;
}
}
I can get around this by using forward iterators and looping through the list to the end, but that's so cumbersome. The compiler is OK with a forward iterator in this context, and I tried casting a the reverse iterator to a const iterator but the compiler didn't like that either.
Erasing a list element from a bidirectional list using a reverse iterator seems like a reasonable thing. Is there something obvious I'm missing here?
I suppose that you can simplify your code snippet doing it the next way:
while (!mylist.empty() && mylist.back()->Type() == unwanted) {
mylist.pop_back();
}
To fix the specific error in your code Can I convert a reverse iterator to a forward iterator?
mylist.erase((pos+1).base());
Using std::reverse_iterator::base
The base iterator refers to the element that is next (from the std::reverse_iterator::iterator_type perspective) to the element the reverse_iterator is currently pointing to.
Anyway, pop_back is the best choice in your case.

Trouble using iterator on a list of objects

So I have a class called symbol, which is made up of 4 strings which are all public. I created a list of these and I want to do a look ahead on this list. This is what I have so far. I looked up the iterator methods and it says it supports the + operator but I get an error for this.
bool parser::parse(list<symbol> myList){
//Will read tokens by type to make sure that they pass the parse
std::list<symbol>::const_iterator lookAhead = myList.begin();
if ((lookAhead + 1) != myList.end)
lookAhead++;
for (std::list<symbol>::const_iterator it = myList.begin(); it != myList.end(); ++it){
if (it->type == "") {
}
}
return true;
}
I get an error when trying to add 1 to lookAhead. What are some good ways of creating a look ahead for a list?
Thanks,
Binx
A linked list does not support random access iterators, i.e. you cannot add an integer to its iterators.
Use std::next(lookAhead) to get the next iterator instead, or std::advance(lookAhead, 1). These functions know what kind of iterator is being passed, and will use a random seek if possible (e.g. with std::vector's random-access iterators), or manually advance (with a loop in the case of std::advance()) otherwise, as in this case.
Be careful advancing on iterators unconditionally, though -- advancing past end() is undefined!
You can read more about the different categories of C++ iterators here.
Side note: You're copying the entire list when it's passed in, since you're passing it by value. You probably want to pass it by reference instead (list<symbol> const& myList). You can also simplify your code using the C++11 auto keyword, which deduces the type automatically from the type of the expression that initializes the variable:
bool parser::parse(list<symbol> const& myList){
// Will read tokens by type to make sure that they pass the parse
auto lookAhead = myList.begin();
if (lookAhead != myList.end() && std::next(lookAhead) != myList.end())
++lookAhead;
for (auto it = myList.begin(); it != myList.end(); ++it){
if (it->type == "") {
}
}
return true;
}

std::find_if for custom objects returns bad iterator when vector has at least 1 element

So I have a vector of objects of type Player. If I try to use std::find_if on that vector and use a lambda expression that return true only if the name if the player is a name I want to check against, it will work the first time if the vector is empty (as in the iterator is nullptr), but once I add a Player object in the vector, the find_if will return an iterator filled with random, bad data.
My code:
auto player = find_if(m_playerList.begin(), m_playerList.end(), [name](Player& p)
{
return p.Name == name;
});
if (player._Ptr != nullptr)
{
// Do stuff
}
else
{
Player newPlayer;
newPlayer.Name = name;
m_playerList.push_back(newPlayer);
}
So in the first iteration of this function, the player is nullptr, because the vector didn't contain any elements. In the second iteration, if I search by the same name, it finds it in the vector, however if I search by a different name, it returns an object with mangled, random data and the check "if (player._Ptr != nullptr)" passes.
Question is, what causes this? Am I checking the "player" object properly to figure out if the find_if actually found a valid object in the vector?
The code you wrote isn't portable because it uses implementation-specific _Ptr member of vector::iterator, and therefore there are no requirements on that member to be nullptr. Change
if (player._Ptr != nullptr)
to
if (player != m_playerList.end())

How to get the last element of an std::unordered_map?

How to get the last element of an std::unordered_map?
myMap.rbegin() and --myMap.end() are not possible.
There is no "last element" in a container that is unordered.
You might want an ordered container, e.g. std::map and access the last element with mymap.rbegin()->first (Also see this post)
EDIT:
To check if your iterator is going to hit the end, simply increment it (and possibly save it in a temporary) and check it against mymap.end(), or, even cleaner : if (std::next(it) == last)
In your comments, it appears your goal is to determine if you are on the last element when iterating forward. This is a far easier problem to solve than finding the last element:
template<class Range, class Iterator>
bool is_last_element_of( Range const& r, Iterator&& it ) {
using std::end;
if (it == end(r)) return false;
if (std::next(std::forward<Iterator>(it)) == end(r)) return true;
return false;
}
the above should work on any iterable Range (including arrays, std containers, or custom containers).
We check if we are end (in which case, we aren't the last element, and advancing would be illegal).
If we aren't end, we see if std::next of us is end. If so, we are the last element.
Otherwise, we are not.
This will not work on iterators that do not support multiple passes.
You cant. by definition, the element is not stored based on some sort of order. the key is hashed first and that's why O(1) search is possible. if you wanna check whether a key exists in the unordered_map or not, u can use this code:
std::unordered_map dico;
if(dico.count(key)!=0){
//code here
}
std::unordered_map::iterator last_elem;
for (std::unordered_map::iterator iter = myMap.begin(); iter != myMap.end(); iter++)
last_elem = iter;
// use last_elem, which now points to the last element in the map
This will give you the last element in whatever order the map gives them to you.
Edit: You need to use std::unordered_map<YourKeyType, YourValueType> instead of just std::unordered_map. I just wrote it like this because you did not provide the type in your question.
Alternatively, as suggested by vsoftco (thanks), you could declare both last_elem and iter as decltype(myMap)::iterator.
(If you're compiling with the MSVC++ compiler, then you will need to add typedef decltype(myMap) map_type; and then instead of decltype(myMap)::iterator use map_type::iterator.)
.end() is an iterator to the "element past the last element". That's why you compare it like this when you loop through a map:
for (auto it = myMap.begin(); it != myMap.end(); ++it) // '!=' operator here makes it possible to only work with valid elements
{
}
So you want the "last" element (whatever that may be, because it's not really guaranteed to be the last in an unordered map, since it ultimately depends on how the key was hashed and in which "bucket" it ends up in). Then you need: --myMap.end()
More specifically, .end() is a function, that returns an iterator, same as .begin() returns an iterator. Since there is no .rbegin() in an std::unordered_map, you have to use -- (the decrement operator):
auto it = --myMap.end();
To access the key you use it->first, to access the value you use it->second.
The accepted answer seems wrong. Unordered_map does have the last element even though the key-value pair is not stored in sorted order. Since the iterator of unorered_map is forwar_iterator(LegacyForwardIterator), the cost to find the last element is O(n). Yakk - Adam gave the correct answer. Essentially, you have to iterator the container from begin to end. At each iteration, you have to check whether the next element is end(); if yes then you are at the last element.
You cannot call prev(it) or --it. There will be no syntax error, but you will have a runtime error (more likely segmentation fault) when using the prev(it) or --it. Maybe next version of compiler can tell you that you have an logic error.
It may not be the best solution, performance-wise, but in C++11 and later, I use a combination of std::next() and size() to jump all elements from the beginning of the map, as shown below:
std::unordered_map<int,std::string> mapX;
...
if (mapX.size() > 0) {
std::unordered_map<int,std::string>::iterator itLast =
std::next(mapX.begin(), mapX.size() - 1);
...