C++ finding something in vector - c++

I have an vector like this:
struct RIFT_MONSTER_SPAWN
{
DWORD dwWorldId;
D3DXVECTOR3 vPos;
};
vector<RIFT_MONSTER_SPAWN> vecMSpawn;
As you can see it will hold 2 values dwWorldId and D3DXVECTOR3 vPos;
vPos will hold x,y,z value.
Now what I want to do is looping true the vector and if the worldId matches the worldId that is beeing passed. It should return the vPos that is releated to the worldId.
If have use std::find find_all and count.
But it always returns the error
binary == no operator found which takes a left hand operator of type
So I am an bit stuck on this. Any help would be appreciated.
With kind regards.
Here is the code that is giving me problems
void CRiftMatch::GetMoverSpawnPoints(dwWorldId)
{
std::vector<RIFT_MONSTER_SPAWN> vecSpawn = CRiftMng::GetInstance()->m_vecMSpawnPoint;
std::vector<RIFT_MONSTER_SPAWN>::iterator it = std::find(vecSpawn.begin(), vecSpawn.end(), dwWorldId);
OUTPUTDEBUGSTRING("\n GetMoverSpawn %d", *it);
}
m_vecMSpawnPoint is defined in .h file as
vector<RIFT_MONSTER_SPAWN> m_vecMSpawnPoint;
Also to fill it i am using this code
while (Lua.TableLoop(-2))
{
RIFT_MONSTER_SPAWN rSpawnPoint;
rSpawnPoint.dwWorldId = static_cast<int>(CScript::GetDefineNum(Lua.GetFieldToString(-1, "dwWorldId")));
rSpawnPoint.vPos.x = static_cast<float>(Lua.GetFieldToNumber(-1, "x"));
rSpawnPoint.vPos.y = static_cast<float>(Lua.GetFieldToNumber(-1, "y"));
rSpawnPoint.vPos.z = static_cast<float>(Lua.GetFieldToNumber(-1, "z"));
m_vecMSpawnPoint.push_back(rSpawnPoint);
Lua.Pop(1);
}

You have to modify your struct to be able compare values during find:
struct RIFT_MONSTER_SPAWN
{
DWORD dwWorldId;
D3DXVECTOR3 vPos;
bool operator () ( const RIFT_MONSTER_SPAWN & m ) const
{
return m.dwWorldId == dwWorldId;
}
};
RIFT_MONSTER_SPAWN monsterToFind;
monsterToFind.dwWorldId = dwWorldId;
it = std::find_if( vecSpawn.begin(), vecSpawn.end(), monsterToFind);
Maybe just a type, but in your code, you have
void CRiftMatch::GetMoverSpawnPoints(dwWorldId)
but it should be
void CRiftMatch::GetMoverSpawnPoints(DWORD dwWorldId)

You could pass a predicate (which can be a lambda) to std::find_if so code
auto it = std::find_if(vecSpawn.begin(), vecSpawn.end(),
[&] (const struct RIFT_MONSTER_SPAWN& sp)
{return sp.dxWorldId == dwWorldIt;});
But in such a case I would simply use a for loop (because I find that more readable):
int ix=0;
for (auto&sp : vecSpawn) {
if (sp.dxWorldId == dwWorldIt)
return vecSpawn.begin() + ix;
ix++;
}

With range/v3, you may simply do
auto it = ranges::find(vecSpawn, dwWorldIt, &RIFT_MONSTER_SPAWN::dxWorldId);
else you have to use more verbose
auto it = std::find_if(vecSpawn.begin(), vecSpawn.end(),
[&](const RIFT_MONSTER_SPAWN& e) {
return e.dxWorldId == dwWorldIt;
});

Related

How can i delete an element from a map into a vector

I'm currently trying for a game project to get rid of a dangling reference when a plane crashes before reaching the terminal it was booked to reach.
I would like to go through <algorithm> functions only to better understand how they work.
At the moment I've tried going through the map that contains all the planes associated with a terminal, comparing it with the list of all the planes and checking if a plane that is in the map is no longer in the vector then delete it from the map to free the associated terminal.
void remove_crashed_aircraft(std::unordered_map<const Aircraft*, size_t>& reserved_terminals, std::vector<std::unique_ptr<Aircraft>>& aircrafts)
{
auto it = std::all_of(reserved_terminals.begin(), reserved_terminals.end(),
[aircrafts](const Aircraft* a1){ return std::find_if(aircrafts.begin(), aircrafts.end(),
[a1](std::unique_ptr<Aircraft> a2){ return a1==a2.get();});});
reserved_terminals.erase(it);
}
And this is my Aircraft class:
class Aircraft : public GL::Displayable, public GL::DynamicObject
{
private:
const AircraftType& type;
const std::string flight_number;
Point3D pos, speed; // note: the speed should always be normalized to length 'speed'
WaypointQueue waypoints = {};
Tower& control;
bool landing_gear_deployed = false; // is the landing gear deployed?
bool is_at_terminal = false;
int fuel = 0;
// turn the aircraft to arrive at the next waypoint
// try to facilitate reaching the waypoint after the next by facing the
// right way to this end, we try to face the point Z on the line spanned by
// the next two waypoints such that Z's distance to the next waypoint is
// half our distance so: |w1 - pos| = d and [w1 - w2].normalize() = W and Z
// = w1 + W*d/2
void turn_to_waypoint();
void turn(Point3D direction);
// select the correct tile in the plane texture (series of 8 sprites facing
// [North, NW, W, SW, S, SE, E, NE])
unsigned int get_speed_octant() const;
// when we arrive at a terminal, signal the tower
void arrive_at_terminal();
// deploy and retract landing gear depending on next waypoints
void operate_landing_gear();
void add_waypoint(const Waypoint& wp, const bool front);
bool is_on_ground() const { return pos.z() < DISTANCE_THRESHOLD; }
float max_speed() const { return is_on_ground() ? type.max_ground_speed : type.max_air_speed; }
bool is_paused = false;
Aircraft(const Aircraft&) = delete;
Aircraft& operator=(const Aircraft&) = delete;
public:
Aircraft(const AircraftType& type_, const std::string_view& flight_number_, const Point3D& pos_,
const Point3D& speed_, Tower& control_, int fuel_) :
GL::Displayable { pos_.x() + pos_.y() },
type { type_ },
flight_number { flight_number_ },
pos { pos_ },
speed { speed_ },
control { control_ },
fuel { fuel_ }
{
speed.cap_length(max_speed());
}
const std::string& get_flight_num() const { return flight_number; }
float distance_to(const Point3D& p) const { return pos.distance_to(p); }
bool is_circling() const
{
if (!has_terminal() && !is_at_terminal)
{
return true;
}
return false;
}
bool has_terminal() const
{
if (waypoints.empty())
{
return false;
}
else
{
return waypoints.back().type == wp_terminal;
}
}
bool is_low_on_fuel() const
{
if (fuel<200)
{
return true;
}
else
{
return false;
}
}
void display() const override;
bool move() override;
void refill(int& fuel_stock);
friend class Tower;
friend class AircraftManager;
};
The code of the function generates errors that I can't understand unfortunately.
use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Aircraft; _Dp = std::default_delete<Aircraft>]’
static assertion failed: result type must be constructible from value type of input range
If anyone has an idea of how I can achieve this, I would be very grateful!
First, you have to use std::remove_if, because std::all_of returns bool, not iterator. But std::remove_if does what you want, it removes all instances that match bool predicate.
Second, your compile errors appear because you pass by value everywhere, so instead of (std::unique_ptr<Aircraft> a2) pass reference (std::unique_ptr<Aircraft> const & a2), instead [aircrafts] and [a1] pass [&aircrafts] and [&a1].
Third, inner predicate should not just return result of std::find_if (which returns iterator) but return bool, i.e. compare result of find_if to aircrafts.end().
Speed-wise your algorithm can be optimized if needed, for that you have to convert std::vector to std::unordered_set and then iterate through first map and check containment inside second set. If you don't have too many elements and speed is not of much importance then your algorithm is alright.
Final working code below:
void remove_crashed_aircraft(
std::unordered_map<const Aircraft*, size_t>& reserved_terminals,
std::vector<std::unique_ptr<Aircraft>>& aircrafts
) {
std::remove_if(reserved_terminals.begin(), reserved_terminals.end(),
[&aircrafts](auto const & a1){
return std::find_if(aircrafts.begin(), aircrafts.end(),
[&a1](auto const & a2){ return a1.first == a2.get(); })
== aircrafts.end();
}
);
}

Iterating over vector of custom object with two conditions

Using C++11, I'd like to iterate over a vector and return a type that indicates that the index was not found.
I am use to the traditional for(;;) loop and specifying the index manually, as my code shows below.
inline std::size_t ItemList::FindItem(Items& Item)
{
for (std::size_t i = 0; i < ItemVector.size(); i++)
{
if (ItemVector[i]->GetId() == Item.GetId() && !ItemVector[i]->GetName().compare(Item.GetName()))
{
return i + 1;
}
}
return 0;
}
I'm also having to increment the index +1 in order to return a value of 0 (to accommodate unsigned size_t) to indicate the calling method that the index was not found (I understand this is asinine). I am assuming it would be more suitable to return something more like std::end()?
Would using a C++11 iterator approach be more efficient? The vector will populate to a large number and the find needs to be quick.
You could use std::find_if and work with iterators:
auto it = std::find_if(ItemVector.begin(), ItemVector.end(),
[&Item](Items *value) {
return value->GetId() == Item.GetId() && !value->GetName().compare(Item.GetName());
}
);
Then you can simply test if it != ItemVector.end() to know if you found something.
There will likely be no (or very small) difference between this and your version in term of speed, but it is a cleaner way to check if something was found or not.
Yes, an iterator would be the way to do this, you're actually writing your own version of find_if You could instead do:
find_if(cbegin(ItemVector), cend(ItemVector), [&](const auto& i){ return i.GetId() == Item.GetId() && i.GetName() != Item.GetName(); })
You can test whether the result of this function was found by testing for equality with cend(ItemVector).
Additionally if you need to find the index of the item you can pass this result after cbegin(ItemVector) to: distance
Live Example
My solution for double search condition that Lambda has multiple parameters in find_if
bool check_second_loop(FullFrame *image_track, guint64 object_id, bool *deletion)
{
auto itr= std::find_if(image_track->track_ids.begin(),
image_track->track_ids.end(),
[object_id](const guint64& a)
{
return a == object_id;
});
if (itr != image_track->track_ids.end())
{
image_track->track_ids.erase(itr);
if(image_track->track_ids.size()==0)
{
*deletion = true;
}
return true;
}
else
return false;
}
bool check_first_loop(guint64 object_id, gint source_id)
{
bool deletion = false;
auto it = find_if(full_frame_list.begin(), full_frame_list.end(),
[object_id, &deletion, source_id](FullFrame &x)
{
return check_second_loop(&x, object_id, &deletion)
&& x.camera_number == source_id;
});
if (it != full_frame_list.end())
{
// Found
return true;
}
else
return false;
}

Std::map \ std::set contain duplicate keys

I have an issue and though I understand, that is kind of a stupid question to ask, but I failed to find a solution on my own.
So, I'm trying to accumulate a container with unique values of a structure I have.
struct Symbol {
D2D1_RECT_F bbox;
wchar_t data;
fz_font_s* font;
float color[4];
};
What I'm doing is trying to use std::map and std::set. Being aware, that I need to provide a predicate in order to give container a way to determine the order. What I have is:
struct SymbolCmp {
bool operator() (const Symbol& lhs, const Symbol& rhs) const
{
auto errorHandler = (lhs.bbox.top == rhs.bbox.top) ? (lhs.bbox.left < rhs.bbox.left) : lhs.bbox.top < rhs.bbox.top;
if (lhs.data == rhs.data &&
lhs.font != rhs.font) {
return errorHandler;
}
float lArea = (lhs.bbox.bottom - lhs.bbox.top) *
(lhs.bbox.right - lhs.bbox.left);
float rArea = (rhs.bbox.bottom - rhs.bbox.top) *
(rhs.bbox.right - rhs.bbox.left);
auto relative = (lArea / rArea < 0.95f ||
lArea / rArea > 1.05f);
return (lhs.data == rhs.data) ? relative && errorHandler : (lhs.data < rhs.data);
}
};
And then I just try inserting values inside of std::set<Symbol, SymbolCmp> and std::map<Symbol, byte, SymbolCmp>.
Sadly enough the results are frustrating, cause what I get is pretty far from an object, containing unique keys only. Most of Symbol's have duplicates.
So I REALLY to understand, what I'm missing?
Your predicate doesn't ensure strict-weak ordering. Following should work:
struct SymbolCmp {
bool operator() (const Symbol& lhs, const Symbol& rhs) const
{
if(lhs.data == rhs.data) {
return (lhs.bbox.top == rhs.bbox.top) ? (lhs.bbox.left < rhs.bbox.left) : lhs.bbox.top < rhs.bbox.top;
} else {
return lhs.data < rhs.data;
}
}
};
If you want to use font, color and dimension in the logic, ensure that your follow the strict-weak ordering constraint.

C++ find_if - How to find an ID (int(

I wanted to find how to use find_if to find the SceneNode based on ID. I am unsure how to do this though.
I was able to for example, do this to remove the SceneNode based on the actual pointer like so:
SceneNode::Ptr SceneNode::detachChild(const SceneNode& node)
{
auto found = std::find_if(mChildren.begin(), mChildren.end(), [&](Ptr& p) -> bool {return p.get() == &node; });
...
but I am unsure on how to deal with find_if if I am looking for SceneNodes mID variable (which is an INT).
I.E.
SceneNode::Ptr SceneNode::findChild(int findID)
{
auto found = std::find_if(mChildren.begin(), mChildren.end(), ... ? = findID?; });
...
Does anyone have any good sites or info for me that explains find_if well? Thanks!
You basically had it...
auto found = std::find_if(
mChildren.begin(),
mChildren.end(),
[&](Ptr& p) -> bool { return p->mID == node.mID; }
);
Based on your first example, it appears that a Ptr & is the result of mChildren.begin().operator*() (or something compatible).
So:
SceneNode::Ptr SceneNode::findChild(int findID)
{
auto found = std::find_if(
mChildren.begin(), mChildren.end(),
[findID](Ptr &ptr)
{
return findID == ptr.get()->mID;
});
...
}
I think you want something like this:
SceneNode::Ptr SceneNode::findChild(int findID)
{
auto found = std::find_if(std::begin(mChildren), std::end(m_children),
[=](Ptr& p) { return p->mID == findID; }
);
// ...
}
This lambda will capture findID by value and compare it with the mID member of what Ptr points to.

C++ how to check if an element of all objects stored in a vector have the same value?

For example I have an vector of objects and they all have attribute PointX so I want to check if all of them have the same value of PointX and if they have it should return true or false whatever.
So in a kind of pseudo-code:
IF ( Object[1].getPointX() == Object[2].getPoint(x) == Object[3].getPoint(x) ){
return true;
}
The problem is that I have more than 55 objects so there has to be a way to compare them without writting them all individually. I know there must be with a for loop but still I have no idea.
thanks in advance.
edit:
#awesomeyi your suggestion seems the easiest and more adequate to my needs (I'm not saying the others are not but I think they are too complicated for a newb like me) but it's not working, even if Xpoints are all the same or different it always returns false. here's what i have:
bool allKilled(){
auto checkpointx = Invader[0].getIfActive();
for(int i = 0; i < 55; ++i){
if(Invader[i].getIfActive() != checkpointx){
return false;}
}
}
the getIfActive() just returns if its true or false, and i want this method to return true if all Active (attribute of the object) of all objects are all false.
Something like this:
auto refx = Object[0].getPointX();
bool b = std::all_of(Object.begin(),
Object.end(),
[refx](TheTypeOfTHeElements& e)
{ return e.getPointX() == ref; });
Obviously you need to check that Objects is not empty.
For loop?
auto checkpointx = Object[0].getPointX();
for(int i = 1; i < Object.size(); ++i){
if(Object[i].getPointX() != checkpointx)
return false;
}
I'd do it something like this:
template<typename Objects, typename Comparison>
bool is_all_same( Objects&& objects, Comparison&& comp ) {
using std::begin; using std::end;
auto&& b = begin(objects);
auto&& e = end(objects);
if (b == e)
return true;
auto&& first = *b;
for( auto&& cur = std::next(first); cur != e; ++cur ) {
if (!comp( first, cur ))
return false;
}
return true;
}
use:
bool all_same_x = is_all_same( objs, []( Obj const& left, Obj const& right )->bool {
return left.getPointX() == right.getPointX();
});
where objs is some container or range containing objects of type Obj.
The above code should work on all standard containers, C style arrays, custom containers that support the new for loops, and is close to optimal performance wise.