Search a Vector of Objects by Object Attribute

Search a vector of objects by object attribute

You can use std::find_if with a suitable functor. In this example, a C++11 lambda is used:

std::vector<Type> v = ....;
std::string myString = ....;
auto it = find_if(v.begin(), v.end(), [&myString](const Type& obj) {return obj.getName() == myString;})

if (it != v.end())
{
// found element. it is an iterator to the first matching element.
// if you really need the index, you can also get it:
auto index = std::distance(v.begin(), it);
}

If you have no C++11 lambda support, a functor would work:

struct MatchString
{
MatchString(const std::string& s) : s_(s) {}
bool operator()(const Type& obj) const
{
return obj.getName() == s_;
}
private:
const std::string& s_;
};

Here, MatchString is a type whose instances are callable with a single Type object, and return a boolean. For example,

Type t("Foo"); // assume this means t.getName() is "Foo"
MatchString m("Foo");
bool b = m(t); // b is true

then you can pass an instance to std::find

std::vector<Type>::iterator it = find_if(v.begin(), v.end(), MatchString(myString));

Find if an object attribute is in the Vector of objects C++

In your situation std::find_if could be the solution

auto it = find_if(c.begin(), c.end(), [&check](const Car& obj) {return obj.getDir() == check;})

find a value in a vector of class objects

I found two solution as for my problem:

  1. You can implement std::find in vector class-based object in c++:

    class A {
    private:
    string b;
    string c;
    public:
    A(string i) : b(i) {}
    A(string n, string l) { b = n ;c = l; }
    string Getb(){ return b; }
    string Getc(){ return c; }
    bool operator==(const A & obj2) const
    {
    return (this->b.compare(obj2.b) == 0);
    }
    };

    int main()
    {
    vector<A> a1;
    a1.push_back(A("AA","aa"));
    a1.push_back(A("BB","bb"));
    a1.push_back(A("CC","cc"));
    a1.push_back(A("DD","dd"));

    auto it = find(a1.begin(), a1.end(), A("CC"));
    if (it != a1.end()) {
    auto idx = distance(a1.begin(), it);
    cout << "b= " << it->Getb() << " c= " << it->Getc() << endl;
    cout << "Index= " << idx << endl;
    } else
    cout << "CC is not found" << endl;
    return 0;
    }
  2. You can implement std::find_if in vector class/structure based object in c++ (thanks to @Vlad from Moscow and @R Sahu):

    class A {
    private:
    string b;
    string c;
    public:
    A(string n, string l) { b = n ;c = l; }
    string Getb(){ return b; }
    string Getc(){ return c; }
    struct Finder {
    Finder(string const & n) : name(n) { }
    bool operator () (const A & el) const {
    return el.Pos == name;
    }
    string name;
    };
    };

    int main()
    {
    vector<A> a1;
    a1.push_back(A("AA","aa"));
    a1.push_back(A("BB","bb"));
    a1.push_back(A("CC","cc"));
    a1.push_back(A("DD","dd"));

    vector<A>::iterator it;
    it = find_if(a1.begin(), a1.end(), A::Finder ("CC"));
    if (it != a1.end()) {
    auto idx = distance(a1.begin(), it);
    cout << "b= " << it->Getb() << " c= " << it->Getc() << endl;
    cout << "Index= " << idx << endl;
    } else
    cout << "CC is not found" << endl;

    return 0;
    }

find objects that have the same value for an attribute in a vector of objects

You would need to define a custom operator== to loop over Pins and pinNumNameMap (incidentally, I just answered another question about comparing custom objects in a vector here).

Here is what I came up with, although it might not be exactly what you need depending on whether you need all the entries in Pins and pinNumNameMap to match exactly or if comparing the size of the containers is enough.

EDIT: I merged the two sections into one to illustrate the possible use.

#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <functional>

struct myObject
{
int numberOfSymbols;
std::list<int> symbolNumbers;
std::list<int> Pins;
std::list<std::string> pinNumList;
std::map<std::string, std::string> pinNumNameMap;

friend bool operator == (const myObject& _this, const myObject& _other)
{
// Check if entry sizes match
if (_this.Pins.size() != _other.Pins.size() ||
_this.pinNumNameMap.size() != _this.pinNumNameMap.size())
{
return false;
}

// Now check if the things inside the entries also match
bool same(true);
for (auto this_it = _this.Pins.begin(), other_it = _other.Pins.begin(); this_it != _this.Pins.end(); ++this_it, ++other_it)
{
same &= (*this_it == *other_it);
}

for (const auto& name : _this.pinNumNameMap)
{
same &= (_other.pinNumNameMap.find(name.first) != _other.pinNumNameMap.end() &&
_other.pinNumNameMap.at(name.first) == name.second);
}
return same;
}

};

// std::reference_wrapper is used when you want to
// store references to objects in a container like
// std::vector (you can't store myObject&)
typedef std::reference_wrapper<myObject> ObjRef;

int main()
{

std::vector<myObject> m_myObject;

// This is your comparison object.
// Use this to identify objectsin the original
// container with matching Pins and pinNumNameMaps.
myObject tmp;
tmp.Pins = {1, 2, 3};
tmp.pinNumNameMap =
{
{"pin 1", "name 1"},
{"pin 2", "name 2"},
{"pin 3", "name 3"}
};

std::vector<ObjRef> objectsWithCertainPins;

for (auto& obj : m_myObject)
{
if (obj == tmp)
{
// Use std::reference_wrapper to avoid
// copying large myObject instances
objectsWithCertainPins.emplace_back(std::ref(obj));
}
}

// Now you can iterate over objects in your
// objectsWithCertainPins container.
for (auto& obj : objectsWithCertainPins)
{
std::cout << "Pins:";
for (const auto& p : obj.get().Pins)
{
std::cout << " " << p;
}
std::cout << "\n";
}

return 0;
}

Iterate through a vector of objects and find a variable that matches one pulled from a text file

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.

Binary search on vector objects of an element greater than an attribute

For std::binary_search to succeed, the range need to be sorted.std::binary_search, std::lower_bound works on sorted containers. So every time you add a new element into your vector you need to keep it sorted.

For this purpose you can use std::lower_bound in your insertion:

class X;
class XCompare
{
public:
bool operator()(const X& first, const X& second) const
{
// your sorting logic
}
};

X value(...);
auto where = std::lower_bound(std::begin(vector), std::end(vector), value, XCompare());
vector.insert(where, value);

And again you can use std::lower_bound to search in your vector:

auto where = std::lower_bound(std::begin(vector), std::end(vector), searching_value, XCompare());

Don't forget to check if std::lower_bound was successful:

bool successed = where != std::end(vector) && !(XCompare()(value, *where));

Or directly use std::binary_search if you only want to know that element is in vector.

Sort a vector of objects by an object's attribute

You should implement an operator< on cat so that cats can be sorted:

class cat {
public:
int age;
bool operator< (const cat &other) const {
return age < other.age;
}
};

You can then include the "algorithm" header and use std::sort on your array:

vector< cat > catSorter::SortCatsByAge(){
vector< cat > cats_copy = cats;
std::sort(cats_copy.begin(), cats_copy.end());
return cats_copy;
}


Related Topics



Leave a reply



Submit