Lambda with multiple parameters in find_if - c++

I've got a vector with objects of a custom data type. One of the fields of this data type is an enum. I want to make sure that for all enum values at least one entry is added to the vector.
I want to use std::find_if() to check if the vector has an entry for a certain enum value. But I'm not sure how to write & use the lambda correctly. Here's what I got:
struct CustomType
{
EnumType type {EnumType::DEFAULT};
int x;
};
std::vector<CustomType> tmp;
// fetch values from database and add them to the vector
// for some EnumType values there might not be a record added to the vector
auto hasEnumType = [](const CustomType& customType, const EnumType& enumType) -> bool
{
return (customType.type == enumType);
};
// What do I replace '?' with to get the current position
if (std::find_if(tmp.begin(), tmp.end(), hasEnumType(?, EnumType::VALUE1)) != tmp.end())
{
//add CustomType with VALUE1 to vector
}

If you want to check against a fixed value, you can simply put it inside the lambda.
if ( std::find_if(tmp.begin(), tmp.end(), [](CustomType const & customType)
{ return customType.type == EnumType::VALUE; }) )
{ /* do something */}
If you want, in a sense, pass it to lambda as parameter, you can set it in an external variable and "capture" it by reference
auto enumType = EnumType::VALUE;
// capture variables by references --------V
if ( std::find_if(tmp.begin(), tmp.end(), [&](CustomType const & customType)
{ return customType.type == enumType; }) )
{ /* do something */ }

std::find_if takes a unary predicate as its third parameter. If you provide binary predicate it will fail type check.
One way to do this is to convert your binary predicate to unary predicate by capturing one of its parameters. To automate it for all enum values create a function that returns another function.
auto getTypeChecker = [](const EnumType enumType)
{
return [enumType](const CustomType& customType)
{
return (customType.type == enumType);
};
};
then declare a function that takes care of inserting enum values that are not present in the vector -
void insert_if_not_present(std::vector<CustomType>& vec, const EnumType type)
{
if(std::none_of(begin(vec), end(vec), getTypeChecker(type)))
{
//add CustomType with type to vec
}
}
Now call insert_if_not_present once for each enum value.
Note, here I have used std::none_of for convenience. You can use std::find_if in place of std::none_of in smae manner.

Related

How can i compare two properties of struct in a single SET?

My code is as below.
I have as struct ABC and i have set g_ABCSet to compare the id.
struct ABC
{
CString name;
byte id[2];
}
typedef shared_ptr<ABC> ABC_PTR;
std::set<ABC_PTR, CompareABC> g_ABCSet;
class ComparePager{
public:
bool operator()(const ABC_PTR& m1, const ABC_PTR& m2) const {
if (m1->id[0] == m2->id[0]){
return m1->id[1] < m2->id[1];
}
return m1->id[0] < m2->id[0];
}
}
I try to search in set as below comparing the id
static ABC_PTR ABCptr(new ABC);
//Assume ABCptr have some valid ID
auto it = g_ABCSet.find(ABCptr);
if (it == g_ABCSet.end())
{
//not found
}
else
{
//found one
}
My query here is can i use the same set to compare the "Cstring name" in the ABC struct.
If YES HOW ??
IF NO , DO i need to make same new set ,overlaod operator to comparing Cstring and insert all same pointers to new set also ??
No you cannot use a single std::set.
Why: Because the set requires the keys to be in 'strict ordering'. Most likely the set uses a tree structure to store it's items and the tree is sorted by the given comparator.
This means also that if you insert multiple items with different names and identical ids, only one items is stored at all (because the Comparator says they are all identical)
You can use std::find_if to search for Cstring name:
CString searchName = "...";
auto it = std::find_if(
g_ABCSet.begin(),
g_ABCSet.end(),
[&](const ABC_PTR& ptr) {
return ptr->name == searchName;
});
If you have a large set of items in g_ABCSet you should do as you wrote: create a second set with a Comparator for 'name'.
Tip: If you use std::array<byte, 2> id instead of byte id[2] your Comparator could be as simple as
class ComparePager{
public:
bool operator()(const ABC_PTR& m1, const ABC_PTR& m2) const {
return m1->id < m2->id;
}
}
Maybe you better use a std::map<std::array<byte, 2>, ABC_PTR> and another std::map<CString, ABC_PTR> for this job. This needs more memory (mostly because of the CString being copied from the g_ABCSet into the map) but get completly rid of the custom Comparators and you cannot accidentally use the wrong set (with the wrong Comparator)

How to use lambda for std::find_if

I am trying to use std::find_if to find an object that matches some criteria. Consider the following:
struct MyStruct
{
MyStruct(const int & id) : m_id(id) {}
int m_id;
};
...
std::vector<MyStruct> myVector; //... assume it contains things
MyStruct toFind(1);
std::vector<MyStruct>::iterator i = std::find_if(myVector.begin(), myVector.end(), ???);
I am not sure what to put in the ???
All the examples I have seen have a lambda that uses a hard-coded value to check for the ID. What I want is to return the iterator/success only if the id of toFind matches the id of one of the items in the vector.
All the examples I have see don't show me how to pass the two parameters
EDIT
Additional info
There are two different scenarios I have to use this for
One in which there is an == operator for the struct
and another in which there is no operator == for the struct - and i can't create one because the criteria for finding a match for this scenario is not as rigid as would be used for an equivalence operator.
(And thanks to all who responded; I was able to use find() in one case and with your help was able to use find_if() for the other)
Try this:
std::find_if(
myVector.begin(), myVector.end(),
[&toFind](const MyStruct& x) { return x.m_id == toFind.m_id;});
Alternatively, if you had defined an appropriate == overload for MyStruct, you could just use find:
std::find(myVector.begin(), myVector.end(), toFind); // requires ==
The find_if version is usually best when you have some kind of heterogeneous lookup, for example if you were just given an int, not a value of MyStruct.
This is where the lambda capture comes into play. Besides saying what type of parameters are to be passed to the lambda you can also say what existing variables are to be used to construct the lambda with. So in this case you would have something like
std::vector<MyStruct>::iterator i = std::find_if(myVector.begin(),
myVector.end(),
[&](const auto& val){ return val.m_id == toFind.m_id; } );
So the [&] says capture all variables used in the body of the lambda by reference. The (const auto& val) makes the operator() of the lambda a template and lets you take in any type. Then in the body we compare what is passed in from find_if to toFind.
You may use the following:
MyStruct toFind(1);
std::vector<MyStruct>::iterator i =
std::find_if(myVector.begin(), myVector.end(),
[&](const auto& e) { return e.id == toFind.id; });
Do as following:
std::find_if(myVector.begin(), myVector.end(),
[&toFind] (const auto &ele) { return ele.m_id == toFind.m_id}; );

need help to search element from vector of struct

I have vector of struct partationPartItemTag_t type
typedef struct partationPartItemTag
{
std::string partition;
std::string partGroupId;
std::string mathTuid;
std::string partNumber;
tag_t itemTag;
}partationPartItemTag_t;
I want to find element from vector having value for partition == 'a' and partGroupId == 'b'
I have written following code and its working fine with C++11
But now i want to modify this code as I do not have c++11 support
partationPartItemTag_t mi={'a', 'b'};
vector<partationPartItemTag_t> searchlist;
searchlist.push_back(mi);
vector<partationPartItemTag_t>::iterator flag = std::search(partationPartItemTagVec.begin(),partationPartItemTagVec.end(),searchlist.begin(),searchlist.end(),[](partationPartItemTag_t &x, partationPartItemTag_t &y){
return ((x.partition.compare(y.partition) == 0) && (x.partGroupId.compare(y.partGroupId) == 0));
});
Please help me to modify this code i saw few posts for function pointer but I am not able to convert this using function pointer
Note: i want to chek value of 2 member in struct and I can not use lambda function or c++11
Thanks in advance.
A lambda is just a convenience functor that was introduced so that you can write these algorithms simpler.
But it's just a convenience. If you can't use them in this case, it's not the end of the world. After all, we couldn't for many many years. The solution is to just go back to using a functor:
struct SearchFor
{
/* ctor omitted for brevity */
std::string partition, partGroupId;
bool operator()(const partationPartItemTag_t& elem) const
{
return elem.partition == partition &&
elem.partGroupId == partGroupId;
}
};
And then use it in-line:
vector<partationPartItemTag_t>::iterator flag =
std::find_if(partationPartItemTagVec.begin(),
partationPartItemTagVec.end(),
SearchFor("a", "b"));
If you need to convert from C++11 to C++098 better option is to replace a lambda with a functor.
Define a functor compare as follows and call it in your algorithm in place of lambda.
struct compare
{
bool operator(partationPartItemTag_t x, partationPartItemTag_t y) const
{
return ((x.partition.compare(y.partition) == 0) &&
(x.partGroupId.compare(y.partGroupId) == 0) );
}
}
std::search(partationPartItemTagVec.begin(),
partationPartItemTagVec.end(),
searchlist.begin(),searchlist.end(),
compare(partationPartItemTag_t &x, partationPartItemTag_t &y) );

Separating vector of objects

I'm writing a function that will separate a vector of objects into two vectors depending on the value of one of their objects. I want it then to return whichever of the vectors.
This is the code I have so far
std::vector<AggregatedQuoteType> OrderBook::get_aggregated_order_book(SellBuyType which_side) const
{
std::vector<AggregatedQuoteType> ret;
std::vector<AggregatedQuoteType>::const_iterator i = v_OrderInfo.begin();
for (; i != v_OrderInfo.end(); ++i)
((*i).get_SB_type()==BUY ? v_BuyOrders : v_SellOrders).push_back((*i));
if(which_side==SELL){
ret = v_SellOrders;
}
else{
ret = v_BuyOrders;
}
return ret;
}
EDIT
I'm getting the following error:
[Error] no matching function for call to 'std::vector::push_back(const AggregatedQuoteType&) const'
You have marked your function get_aggregated_order_book as const.
OrderBook::get_aggregated_order_book(SellBuyType which_side) const
^^^^^
Here!
The const keyword in C++ implies that you will not be making changes to any members in your class, which I presume v_BuyOrders and v_SellOrders are.
If you're modifying the members of your OrderBook class, you need to make the method non-const.
Do you need the v_BuyOrders and v_SellOrders populated at all or just return whatever matches which_side? If the latter, how about just applying a copy_if operation and return the result?
std::vector<AggregatedQuoteType> ret;
std::copy_if(v_OrderInfo.cbegin(), v_OrderInfo.cend(), std::back_inserter(ret),
[=](const AggregatedQuoteType &at) { return at.get_SB_type() == which_side) };
return ret;
EDIT: not using lambda/C++11,
struct pred {
SellBuyType type;
pred(SellBuyType t) : type(t) {}
bool operator()(const AggregatedQuoteType &at) {
return at.get_SB_type() != type; // Copies the elements for which this returns false
}
};
std::remove_copy_if(v_OrderInfo.cbegin(), v_OrderInfo.cend(), std::back_inserter(ret), pred(which_side));
Do note however that remove_if/remove_copy_if doesn't actually remove anything, just shifts the "removed" elements to the back of the vector. If you want to remove the elements as well use vector::erase on the return value of remove_copy_if.

Access to map data

I have a complex map that defined
typedef short short1
typedef short short2
typedef map<short1,short2> data_list;
typedef map<string,data_list> table_list;
I have a class that fill table_list
class GroupingClass
{
table_list m_table_list;
string Buildkey(OD e1){
string ostring;
ostring+=string(e1.m_Date,sizeof(Date));
ostring+=string(e1.m_CT,sizeof(CT));
ostring+=string(e1.m_PT,sizeof(PT));
return ostring;
}
void operator() (const map<short1,short2>::value_type& myPair) {
OD e1=myPair.second;
string key=Buildkey(e1);
m_table_list[key][e1.m_short1]=e1.m_short2;
}
operator table_list() {
return m_table_list;
}
};
and I use it by
table_list TL2
GroupingClass gc;
TL2=for_each(mapOD.begin(), mapOD.end(), gc);
but when I try to access to internal map I have problems
for example
data_list tmp;
tmp=TL2["AAAA"];
short i=tmp[1]; //I dont update i variable
and when debug it, I see code try add new value to map.then when tmp var is const this cause to a error
but if i use a loop by itrator this work properly
why this no work at first way
thanks herzl
std::map<Key,Value>::operator[](Key const& k) will look for key k. If it's not found, it will insert a new Value() and return a reference to that. This is a modifying operation. Therefore, operator[] is non-const.
The code does not make sense. What is OD? myPair.second would be short in operator() but then you do e1.m_short2 which does not make any sense.
Your likely bug is that for_each takes its 3rd parameter by value which means it is going to make copies of that map and probably you will lose the changes.
You can force for_each to take the 3rd value by reference either by specifying the template parameter directly or by wrapping in boost::ref. However you would do far better to make your functor take the map it is building by reference in its constructor rather than have an instance of a map.
class GroupingClass
{
table_list & m_table_list;
string Buildkey(OD e1)
{
string ostring;
ostring+=string(e1.m_Date,sizeof(Date));
ostring+=string(e1.m_CT,sizeof(CT));
ostring+=string(e1.m_PT,sizeof(PT));
return ostring;
}
public:
explicit GroupingClass( table_list & the_table_list ) :
m_table_list( the_table_list )
{
}
void operator() (const map<short1,short2>::value_type& myPair) const
{
OD e1(myPair.first); // probably what you meant
string key=Buildkey(e1);
m_table_list[key][e1.m_short1]=e1.m_short2;
// did you mean m_table_list[key][myPair.first] = myPair.second; ?
}
};
and use it by
table_list TL2;
for_each(mapOD.begin(), mapOD.end(), GroupingClass(TL2));