Binary search on the vector of structs - c++

I have a vector of structs that contains struct with this architecture
struct Main{
int mainID;
string mainDIV;
string mainNAME;
}
is it possible to use binary search on struct? I know its easy to use on value using
binary_search( vector.begin() , vector.end() , 5 )
But is there a way how to pass callback or something to actually find attribute of struct? I fail to find anything related to thi topic.

Yes, it's possible. The value that std::binary_search takes is only meaningful when compared to the elements of the container. In the simple case (if Main supports operator< somewhere), you would provide an element of type Main as the value:
// check if this specific Main exists
bool yes = std::binary_search(v.begin(), v.end(), Main{0, "some", "strings"});
// does exactly the same thing as above
bool yes = std::binary_search(v.begin(), v.end(), Main{0, "some", "strings"}
, std::less<Main>{});
If it doesn't support operator< (or your container is ordered by something else, e.g. mainID), then you will have to provide a comparator yourself that the algorithm will use:
// check if there is a Main with mainID 5
bool yes = std::binary_search(v.begin(), v.end(), 5,
[](const Main& element, const int value) {
return element.mainID < value;
});

You have to provide information to binary_search() to tell it how to compare your objects. The two most common ways, are to either add an operator<() to the struct if that is possible, or provide a helper function that can compare two structs.
The first form would look something like this:
struct Main {
int mainID ;
string mainDIV ;
string mainNAME ;
bool operator<(const Main & other) const
{
return mainID < other.mainID ;
}
}
This will only compare on on mainID, but you can expand it from there.
Also, this only teaches the compiler how to compare two struct Main, while #Barry's answer above will match an int and a struct Main. But lets keep going with this answer.
Now to find the record for 5, we have to make it into a struct Main:
struct Main search_key = { 5 } ;
bool yes = std::binary_search( v.begin(), v.end(), search_key ) ;
Now, this isn't very elegant, and besides if you have a constructor for struct Main ( and haven't put it in your example ), this won't even work. So we add another constructor just for int.
struct Main
{
Main(int id, const string & a_div, const string & a_name ) : id(id), div(a_div), name(a_name) { }
Main(int id) : id(id) { }
int id ;
string div, name ;
bool operator<(const Main &o) const { return id < o.id ; }
} ;
Now we can do a slightly shorter form:
bool has_3 = std::binary_search( v.begin(), v.end(), Main( 3) ) ;
Historical note: Bjarne has been trying for quite some time to get default comparison operators into the standard, but not everyone was excited about it at the standards meetings. I though there was some progress on it at the last meeting and so it may eventually appear when C++17 is a thing.

Related

Pattern for dynamically setting an order based on contents of a std::vector<string>

I am currently struggling coming up with an optimized method for dynamic ordering. I currently have a vector that looks like this in some place of my code
std::vector<std::string> vec {
"optionB",
"optionA",
"optionC"
};
The items in the above vector can be shuffled.The items in this vector are inserted in a specific order so the above order can be different. For simplicity sakes I added the items during declaration.There are about 9 items in the actual case for simplicity I am using only 3 string items.
Now somewhere else in my code I have something like this.
void filter()
{
bool _optionA,_optionB,_optionC
...
//These boolean variables get assigned values
...
...
/*
Todo : I would like to change the ordering of the
following code based on the ordering of items in the
vector. Currently its in the order _optionA _optionB,
_optionC. I would like this ordering to be based
on the order of the strings as in the above vector.
so it should be _optionB,_optionA,_optionC ,
I understand the items in the vector are string
and the following are boolean types
*/
if(_optionA){
}
if(_optionB) {
}
if(_optionC){
}
}
The simplest approach that comes to my mind is
for(auto str : vec)
{
if( (str=="optionA" && _optionA))
{
//This was optionA
}
else if( (str=="optionB" && _optionB)) {
}
else if( (str=="optionC" && _optionC)) {
}
}
I want to know what would be the most optimized way to accomplish the above task ? I am looking for a solution that would avoid iterating through a vector since its in a performance centric piece of code. Is there a way for me to use integrate bitwise operations or something like array indexing to accomplish this task ? Please let me know if something is unclear
It sounds like you want map a string to an actual process. Could you create an interface option class and have instances of options mapped to the string that should cause them to occur? That way you could use the string as a key to get back an Option object and call something like myOption.execute().
The downside to this method is that you need to create a new option class and have it inherit from the interface each time you need a new option.
#Edit: Sorry I think I may have misunderstood the question. But I think the premise still applies you could have a map of string to boolean and just use the string as a key to get back whether the option is toggled on or off.
Assuming you load the vector in on start up, you can sort it at that point to your liking. For example, in alphabetical order. This will mean that you know the order of the vector therefore you can simply reference the vector by index when checking in the your filter function.
Load in data into vector std::vector<string> data = {"optionA", "optionB"};.
Sort using std::sort(data.begin, data.end); or any other sort method of your choice.
Then in you filter function check the vector based on index. if (data.at(1) == "optionA") { }
If I understand your problem correctly, you need to imply order_by on the boolean variables/predicates.
In the below program I will refer your (_optionA, _optionB, _optionC) as predicates even though they are bool, since we can upgrade this problem to work with predicates as well.
Based on the above assumption, I am going ahead with an implementation.
You should pass an ordered_predicates to your filter function.
ordered_predicates is sorted according to your desired criteria.
filter()'s job is just to execute them in the order defined.
auto filter(std::vector<bool> const & ordered_predicates)
-> void
{
for (auto const & condition : ordered_predicates) {
if (condition) {
// ... do your usual stuff here
}
}
}
So how should we go ahead to achieve this ordered_predicates?
We will create a function called order_by that will take an order_by_criteria and a mapping, which will help it in creating ordered_predicates.
With this function, creating ordered_predicates is just a one time cost.
auto order_by(std::vector<std::string> const & order_by_criteria,
std::map<std::string, bool> const & mapping)
-> std::vector<bool>
{
std::vector<bool> ordered_predicates;
for (auto const & item : order_by_criteria)
ordered_predicates.push_back(mapping.at(item));
return ordered_predicates;
}
Where order_by_criteria is your std::vector<std::string> and mapping is just a map which tells which string and predicates are associated.
std::vector<std::string> order_by_criteria { "optionB", "optionA", "optionC" };
std::map<std::string, bool> mapping = { {"optionA", _optionA },
{"optionB", _optionB },
{"optionC", _optionC } };
Here is a complete working program for your reference.
#include <iostream>
#include <map>
#include <vector>
auto order_by(std::vector<std::string> const & order_by_criteria,
std::map<std::string, bool> const & mapping)
-> std::vector<bool>
{
std::vector<bool> ordered_predicates;
for (auto const & item : order_by_criteria)
ordered_predicates.push_back(mapping.at(item));
return ordered_predicates;
}
auto filter(std::vector<bool> const & ordered_predicates)
-> void
{
for (auto const & condition : ordered_predicates) {
if (condition) {
// ... do your usual stuff here
}
}
}
int main()
{
bool _optionA = true, _optionB = false, _optionC = true;
std::vector<std::string> order_by_criteria { "optionB", "optionA", "optionC" };
std::map<std::string, bool> mapping = { {"optionA", _optionA },
{"optionB", _optionB },
{"optionC", _optionC } };
auto ordered_predicates = order_by(order_by_criteria, mapping);
filter(ordered_predicates);
filter(ordered_predicates); // call as many times as you want, with pre-decided order
return 0;
}
If I got the problem correctly, sorting is a way to go. Just sort the vector together with bool flags, using std::vector values as keys, and then simply check bool flags in fixed, lexicographic, order.
Suppose we have a vector {"optB", "optC", "optA"}. After sorting, the indices {0, 1, 2} will rearrange: std::size_t perm[] = {2, 0, 1}. Using this information, that can be precomputed (outside filter(...)), we can rearrange the bool flags:
bool options[N];
// populate options...
bool new_options[N];
for (std::size_t i = 0; i < N; ++i)
new_options[perm[i]] = options[i];
Now we simply check new_options successively:
if (new_options[0]) {
...
}
if (new_options[1]) {
...
}
To precompute perm array use std::map:
std::map<std::string, std::size_t> map;
for (std::size_t i = 0; i < N; ++i)
map.emplace(vec[i], i);
std::size_t perm[N];
auto m = map.begin();
for (std::size_t i = 0; i < N; ++i, ++m)
perm[i] = m->second;

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 map::equal_range without a copy of the object?

I have a performance-sensitive function which uses a map<string, ...> to store some data.
I need to be able to look up values with any substring of some other string as the key, without creating an intermediate string (i.e., the goal is to prevent a heap allocation from happening merely because I want to look something up).
The obvious solution is to hold two separate data structures (perhaps with another map on the side, to map from some key to to each string) -- one for the strings, and one for references to those strings.
But I'm wondering, is there a better way to do this with just a map alone, or do I need another data structure? I'd like to avoid creating too many extra indirections if possible.
Sorry if I misunderstood, but would your problem be solved if you could use a "substring view" of the query string to search the multi-map, instead of an ordinary std::string object?
In that case something along the lines below would work (using C++11-based coding):
Define a substring-view object type. It is constructed from a string and (from,to) offsets, but does not make a copy of the substring:
class substrview
{
std::string::const_iterator _from;
std::string::const_iterator _to;
public:
substrview(
const std::string &s,
const std::size_t from,
const std::size_t to)
: _from(s.begin()+from), _to(s.begin()+to)
{ }
std::string::const_iterator begin() const
{ return _from; }
std::string::const_iterator end() const
{ return _to; }
};
In order to search the multi-map using the substring view, I suggest using the std::lower_bound and std::upper_bound methods from <algorithm>:
int main()
{
std::multimap<std::string,int> map {
{ "hello" , 1 },
{ "world" , 2 },
{ "foo" , 3 },
{ "foobar" , 4 },
{ "foo" , 5 },
};
std::string query { "barfoo" };
/* Search for all suffixes of "barfoo", one after the other: */
for (std::size_t i = 0 ; i < query.size() ; ++i) {
substrview subquery { query,i,query.size() };
auto found_from = std::lower_bound(begin(map),end(map),subquery,cmpL);
auto found_to = std::upper_bound(begin(map),end(map),subquery,cmpU);
/* Now [found_from,found_to) is the match range in the multi-map.
Printing the matches: */
while (found_from != found_to) {
std::cout << found_from->first << ", " << found_from->second << '\n';
++found_from;
}
}
}
For this to work, we only need to define the comparison operators cmpL and cmpU (one for lower_bound, the other for upper_bound – we need two because the comparison is assymetric: comparing a multi-map entry to a substringview in cmpL, and comparing a substringview to a multi-map entry in cmpU):
inline bool cmpL(
const std::pair<std::string,int> &entry,
const substrview &val)
{
return std::lexicographical_compare
(entry.first.begin(),entry.first.end(),val.begin(),val.end());
}
inline bool cmpU(
const substrview &val,
const std::pair<std::string,int> &entry)
{
return std::lexicographical_compare
(val.begin(),val.end(),entry.first.begin(),entry.first.end());
}
Working gist of the complete code: https://gist.github.com/4070189
You need a string_ref type which participates in the < relation with std::string. In the TS n3442, Jeffrey Yaskin proposes introducing a string_ref type influenced by Google's StringPiece and llvm's StringRef. If you can use either of those then you're pretty much done; otherwise writing your own to the proposed interface should be fairly easy, especially as you only need a subset of the functionality.
Note that if you have an implicit constructor from std::string:
string_ref(const std::string &s): begin(s.begin()), end(s.end()) {}
then the < relation with std::string comes for free.

Find array element by member value - what are "for" loop/std::map/Compare/for_each alternatives?

Example routine:
const Armature* SceneFile::findArmature(const Str& name){
for (int i = 0; i < (int)armatures.size(); i++)
if (name == armatures[i].name)
return &armatures[i];
return 0;
}
Routine's purpose is (obviously) to find a value within an array of elements, based on element's member variable, where comparing member variable with external "key" is search criteria.
One way to do it is to iterate through array in loop. Another is to use some kind of "map" class (std::map, some kind of vector sorted values + binarySearch, etc, etc). It is also possible to make a class for std::find or for std::for_each and use it to "wrap" the iteration loop.
What are other ways to do that?
I'm looking for alternative ways/techniques to extract the required element.
Ideally - I'm looking for a language construct, or a template "combo", or a programming pattern I don't know of that would collapse entire loop or entire function into one statement. Preferably using standard C++/STL features (no C++0x, until it becomes a new standard) AND without having to write additional helper classes (i.e. if helper classes exist, they should be generated from existing templates).
I.e. something like std::find where comparison is based on class member variable, and a variable is extracted using standard template function, or if variable (the one compared against "key"("name")) in example can be selected as parameter.
The purpose of the question is to discover/find language feature/programming technique I don't know yet. I suspect that there may be an applicable construct/tempalte/function/technique similar to for_each, and knowing this technique may be useful. Which is the main reason for asking.
Ideas?
If you have access to Boost or another tr1 implementation, you can use bind to do this:
const Armature * SceneFile::findArmature(const char * name) {
find_if(armatures.begin(), armatures.end(),
bind(_stricmp, name, bind(&string::c_str, bind(&Armature::name, _1))) == 0);
}
Caveat: I suspect many would admit that this is shorter, but claim it fails on the more elegant/simpler criteria.
Sure looks like a case for std::find_if -- as the predicate, you could use e.g. a suitable bind1st. I'm reluctant to say more as this smacks of homework a lot...;-).
Why 5 lines? Clean doesn't have a number attached to it. In fact, clean code might take more lines in the utility classes, which can then be reused over and over. Don't restrict yourself unnecessarily.
class by_name
{
public:
by_name(const std::string& pName) :
mName(pName)
{}
template <typename T>
bool operator()(const T& pX)
{
return pX.name == pName;
}
private:
std::string mName;
};
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
Within restriction:
class by_name { public: by_name(const std::string& pName) : mName(pName) {} template <typename T> bool operator()(const T& pX) { return pX.name == pName; } private: std::string mName; };
Then:
const Armature* SceneFile::findArmature(const char* name)
{
// whatever the iterator type name is
auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
return iter == armatures.end() ? 0 : &(*iter);
}
:)
C++0x has ranged-based for-loops, which I think would make the most elegant solution:
const Armature* SceneFile::findArmature(const std::string& pName) const
{
for (auto a : armatures)
{
if (a.name = pName) return &a;
}
return 0;
}
You would probably need to use STL map. It gives you possibility to get the element using keys. Your key would be the name of armature.
http://www.cplusplus.com/reference/stl/map/
EDIT: :D
one liner B-)
const Armature* SceneFile::findArmature(const Str& name){for (int i = 0; i < (int)armatures.size(); i++) if(name == armatures[i].name) return &armatures[i]; return 0;}
Holy shiz, you're using _stricmp? FAIL. Also, you didn't actually tell us the type of the vectors or any of the variables involved, so this is just guesswork.
const Armature* SceneFile::findArmature(const std::string& lols) {
for(auto it = armatures.begin(); it != armatures.end(); it++) {
if (boost::iequals(lols, (*it).name))
return &(*it);
return NULL;
}
Ultimately, if you need this, you should put the armatures or pointers to them in a std::map. A vector is the wrong container if you're searching into it, they're best for when the collection is what's important rather than any finding behaviour.
Edited to use a std::string reference.

Building a vector from components contained in another vector type

I have a code that looks something like this:
struct First
{
int f1;
int f2;
};
struct Second
{
First s1;
int s2;
};
std::vector < Second > secondVec;
Second sec;
sec.s1 = First();
secondVec.push_back(sec);
secondVec.push_back(sec);
std::vector < First > firstVec;
firstVec.reserve(secondVec.size());
for (std::vector < Second >::iterator secIter = secondVec.begin();
secIter != = secondVec.end();
++secIter)
{
firstVec.push_back(secIter->s1);
}
I'd like to replace this ugly for loop with a simple stl function that could perhaps perform the equivalent process. I was thinking that maybe std::transform could help me here, but I'm unsure as to how this could be written.
I'd also be interested if boost has anything to offer here.
If you have TR1 or Boost available, you could try this:
std::transform(secondVec.begin(),
secondVec.end(),
std::back_inserter(firstVec),
std::tr1::bind(&Second::s1, _1));
Define functor that will transform Second to First:
struct StoF { First operator()( const Second& s ) const { return s.s1; } };
Then use it in the following way:
transform( secondVec.begin(), secondVec.end(), back_inserter(firstVec), StoF() );
If your source vector contains a lot of elements you should consider resizing destination vector to make it work faster, as in #Goz answer:
firstVec.resize( secondVec.size() );
transform( secondVec.begin(), secondVec.end(), firstVec.begin(), StoF() );
Its not particularly difficult ... I tried this and it worked no problems.
struct First
{
int f1;
int f2;
};
struct Second
{
First s1;
int s2;
};
First Replace( Second& sec )
{
return sec.s1;
}
and then used the following code to copy it
std::vector < Second > secondVec;
Second sec;
sec.s1.f1 = 0;
sec.s1.f2 = 1;
secondVec.push_back(sec);
sec.s1.f1 = 2;
sec.s1.f2 = 3;
secondVec.push_back(sec);
std::vector < First > firstVec;
firstVec.resize( secondVec.size() );
std::transform( secondVec.begin(), secondVec.end(), firstVec.begin(), Replace );
You were right with your intuition. Although since you are using an empty vector, you should use a back inserter for your output iterator.
It should look like something of the like :
std::transform(secondVec.being(), secondVec.end(), back_inserter(firstVec), yourFunctor)
And yourFunctor looking like this :
void youFunctor(First param)
{
return param.s1;
}
Edit : Boost could help you with lambda function so you wouldn't have to create a separate functor for this task. You should also note that lambda function function are part of the TR1 and will be integrated to the C++ standard library.
Edit : Here is what Meredith was talking about with mem_fun (or member function adaptor).
struct Second
{
First s1;
int s2;
First getS1() const {return s1;};
};
And then the transform would look like this :
std::transform(secondVec.being(),
secondVec.end(),
std::back_inserter(firstVec),
std::mem_fun(&Second::getS1))