In following peace of code, I'm trying to find another object that has the same coordinates as this. How to do it correctly?
auto& organism_vector = world->get_vector();
auto attacked_organism = find_if(begin(organism_vector), end(organism_vector), [this](const unique_ptr<Organism>& attacked_organism)
{
return this->get_coordinates() == attacked_organism->get_coordinates() && *this != *attacked_organism;
});
Another thing, when I finally manage to get this iterator, how to refer to attacked_organism class methods?
*attacked_organism.get_coordinates();
Change *this != *attacked_organism to this != attacked_organism.get():
auto& organism_vector = world->get_vector();
auto attacked_organism = find_if(begin(organism_vector), end(organism_vector),
[this](const unique_ptr<Organism>& attacked_organism)
{
return this->get_coordinates() == attacked_organism->get_coordinates() && this != attacked_organism.get();
}
);
Once you have the iterator that find_if() returns (and after you validate that it is not the end iterator), you can call methods on the Organism by first dereferencing the iterator to access the unique_ptr that is holding the Organism* pointer, and then dereferencing the unique_ptr to access the Organism itself:
auto attacked_organism = find_if(...);
if (attacked_organism != end(organism_vector))
{
(**attacked_organism).get_coordinates();
or:
(*attacked_organism)->get_coordinates();
...
}
On a side note: I would not recommend giving your iterator variable the same name as the lambda parameter. That just makes things confusing to read. The lambda is trying to find an Organism to attack, but it hasn't actually been attacked yet, so you should name the lambda parameter more appropriately, eg:
auto attacked_organism = find_if(begin(organism_vector), end(organism_vector),
[this](const unique_ptr<Organism>& candidate_organism)
{
return this->get_coordinates() == candidate_organism->get_coordinates() && this != candidate_organism.get();
}
);
For that matter, I wouldn't really suggest naming the iterator as attacked_organism, either. It is not the actual Organism, it is an iterator to the Organism, so something more like this would be more readable:
auto& organism_vector = world->get_vector();
auto found_iterator = find_if(begin(organism_vector), end(organism_vector),
[this](const unique_ptr<Organism>& candidate_organism)
{
return this->get_coordinates() == candidate_organism->get_coordinates() && this != candidate_organism.get();
}
);
if (found_iterator != end(organism_vector))
{
auto &attacked_organism = *found_iterator;
attacked_organism->get_coordinates();
...
}
Related
I am trying to return null if the accountNo wasn't find the the map.
But I have only used linkedlist in the past in java.
I have no idea how to return something else in c++ map.
113 Account Bank::BalanceEnquiry(long accountNo){
114 map<long, Account>::iterator itr = accounts.find(accountNo);
115 return itr->second;
116 }
Can anyone help?
You can use std::optional, which is a wrapper that may or may not contain a value:
std::optional<Account> Bank::BalanceEnquiry(long accountNo){
auto itr = accounts.find(accountNo);
if(itr == accounts.end()) {
return std::nullopt; // empty value, that's like null from Java
}
return std::optional<Account>{itr->second}; // return non-empty value
}
It can be used like this (with a Bank-object myBank):
std::optional<Account> balanceEnquiry = myBank.BalanceEnquiry(someValue);
if(balanceEnquiry) {
// entry found, we can extract the actual value
Account foundAccount = balanceEnquiry.value();
}
else {
// entry not found
}
Unlike Java in C++ you can return object by value (or by reference) or by pointer. If you are returning by value (as in your code) you cannot return nullptr unless your class Account has special state. So you have to change return type. Possible variants:
// return a pointer
Account *Bank::BalanceEnquiry(long accountNo){
auto itr = accounts.find(accountNo);
return itr == accounts.end() ? nullptr : &(itr->second);
}
// usage
auto account = bank.BalanceEnquiry(123);
if( account ) account->do_something();
// return std::optional
std::optional<Account> Bank::BalanceEnquiry(long accountNo){
auto itr = accounts.find(accountNo);
return itr == accounts.end() ? std::optional<Account>() : itr->second;
}
// usage
auto account = bank.BalanceEnquiry(123);
if( account ) account.value().do_something();
I have two lists which contain a bunch of elements of the same type:
std::list<Part> allParts = step.getSubParts();
std::list<Part> toRemove;
for (Part part : allParts)
{
for (Part partTwo : allParts) {
if (part.getEdges() == partTwo.getEdges())
if (part.getFaces() == partTwo.getFaces())
if (part.getShells() == partTwo.getShells())
if (part.getVertices() == partTwo.getVertices())
if (part.getWires() == partTwo.getWires())
{
part.addAmount(1);
toRemove.push_back(partTwo);
}
}
}
I have tried iterating through both and remove from the one but I'm constantly getting the list iterators are incompatible error. This is my latest attempt:
std::list<Part>::iterator it;
for (it = step.getSubParts().begin(); it != step.getSubParts().end();)
{
std::list<Part>::iterator i;
for (i = toRemove.begin(); i != toRemove.end();)
{
if (it->getEdges() == i->getEdges())
if (it->getFaces() == i->getFaces())
if (it->getShells() == i->getShells())
if (it->getVertices() == i->getVertices())
if (it->getWires() == i->getWires())
{
it = step.getSubParts().erase(it);
}
else
{
it++;
}
i++;
}
}
Everything I have tried doesn't work. What is the correct way to do this?
You should consider remove_if or erase_if rather than doing your own erase with the hazard of making iterator invalid within a loop.
By the way, you should write predicate like:
if (it->getEdges() == i->getEdges() &&
it->getFaces() == i->getFaces() &&
it->getShells() == i->getShells() &&
it->getVertices() == i->getVertices() &&
it->getWires() == i->getWires()) {
// do something
}
Your code makes people difficult to understand your purpose(at least me).
erase and erase_if
First of all, it would be a good idea to follow the Don't Repeat Yourself principle and write a comparison function for future use:
auto compare_parts = [](const Part& p1, const Part& p2) -> bool {
return ( (p1.getEdges() == p2.getEdges())
and (p1.getFaces() == p2.getFaces())
and (p1.getShells() == p2.getShells())
and (p1.getVertices() == p2.getVertices())
and (p1.getWires() == p2.getWires()) );
}
You would rewrite the first cycle using it and see how much more simple it looks.
Then why not use c++ built-in methods to erase the elements from the list using the function we wrote? This uses new feature in c++ called binding parameters that would aid us here
#include <functional>
using namespace std::placeholders;
for (auto&& badPart : toRemove) {
auto isBad = std::bind(compare_parts, badPart, _1);
step.getSubParts().remove_if(isBad);
}
And that's how you remove special entries from the list.
I think the cleanest way would be:
1. Implement equality operator for the class Part
You can either put it inside or outside the class, it would look like this if you implement it as an external function
inline bool operator==(const Part& lhs, const Part& rhs) {
return lhs.getEdges() == rhs.getEdges() &&
lhs.getFaces() == rhs.getFaces() &&
lhs.getShells() == rhs.getShells() &&
lhs.getVertices() == rhs.getVertices() &&
lhs.getWires() == rhs.getWires();
}
2. Implement the loop, I would recommend using iterators
This is just one way of doing it
if (allParts.size() > 1) {
for(auto partIt = std::begin(allParts); partIt != std::end(allParts); partIt++) {
for(auto partIt2 = std::next(partIt); partIt2 != std::end(allParts);) { // Manual increasing because we erase stuff
if(*partIt == *partIt2) { // Previously implemented equility operator
partIt->AddAmount(1);
partIt2 = allParts.erase(partIt2); // If erase, use the returned iterator as your next `Part`
} else {
partIt2++; // Only increment if nothing was erased (when you erase iterators get invalidated)
}
}
}
}
So I have a vector of objects
vector<Module*> moduleVector;
and I need to iterate through it and compare an attribute from the object to another attribute I'm pulling from a text file
I'm using an ifstream and getLine() to store the element that needs to be compared to the object's attribute (fileD is the opened file, markModId is the string variable)
getline(fileD, markModId, ' ');
But I am unsure of how I can refer to the object's attributes in an iterator. So my question is,
how do I compare the attribute from the file to the object using an iterator?
For reference here is my object constructor (id is the attribute I want to compare)
Module::Module(string id, string title, string lecturer, int
courseworkWeight)
{
code = id;
name = title;
lect = lecturer;
cwWeight = courseworkWeight;
exMark = 0; //ex mark initialised as 0
/*
Map to store coursework marks
*/
map<string, float> CWmarks;
//cwMarks.clear(); //cw marks map cleared
//create a map that stores
}
And exMark is the attribute that needs to be added to the object. All attributes in the Module constructor are private.
How do I compare the attribute from the file to the object using an
iterator?
Short answer: Suppose you have an iterator std::vector<Module*>::iterator iter you can access the public members of Module class like:
(*iter)->/*public member*/;
Long answer: First of all, you need a getter for private member id and one setter for exMark, by which you can get the id of each Module and compare to the id from the file and then set its exMark to some value.
std::string getId()const { return code; }
void setExMark(const double newMark) { exMark = newMark; }
If you want to change the first true instance of Module, you can use std::find_if for finding the Module:
std::string idFromFile = "two";
auto Condition = [&idFromFile](Module* element){ return element->getId() == idFromFile; };
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(), Condition);
if(iter != moduleVector.end())
(*iter)->setExMark(10.0); // see this
// ^^^^^^^^^
See a sample code here
For multiple instances you can do:
for(auto iter = moduleVector.begin(); iter != moduleVector.end(); ++iter)
if ( (*iter)->getId() == idFromFile)
(*iter)->setExMark(10.0);
Note: In modern C++ you can use smart pointers, instead of raw pointers, which will delete the objects automatically as it goes out of scope.
Simply dereference the iterator to access its Module* pointer, then you can access the object using operator-> however you want, eg:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
m->exMark = ...;
}
Or, if you are using C++11 or later, let the compiler handle the iterator for you:
for (Module *m : moduleVector)
{
if (m->code == markModId)
m->exMark = ...;
}
Or, use a lambda with one of the standard iteration algorithms, eg:
std::for_each(moduleVector.begin(), moduleVector.end(),
[&](Module *m)
{
if (m->code == markModId)
m->exMark = ...;
}
);
If you are only interested in updating 1 Module, then break the loop when the the desired Module is found:
for (std::vector<Module*>::iterator iter = moduleVector.begin(), end = moduleVector.end(); iter != end; ++iter)
{
Module *m = *iter;
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
for (Module *m : moduleVector)
{
if (m->code == markModId)
{
m->exMark = ...;
break; // <-- add this
}
}
auto iter = std::find_if(moduleVector.begin(), moduleVector.end(),
[&](Module *m) { return (m->code == markModId); });
if (iter != moduleVector.end())
{
Module *m = *iter;
m->exMark = ...;
}
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.
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.