behaviour of binary predicate for stl map and multimap.... - c++

I have the following code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <map>
using namespace std;
struct vals
{
int cods[5];
int sz;
};
struct myComp
{
bool operator()(vals A, vals B) const
{
int i=0;
while(A.cods[i]==B.cods[i] && i<A.sz)
i++;
if(i==A.sz)
return false; //<-----this is the value im changing..
else
return A.cods[i] > B.cods[i];
}
};
map< vals, int, myComp> Mp;
int main()
{
vals g, h;
g.sz=h.sz=3;
g.cods[0] = 12;
g.cods[1] = 22;
g.cods[2] = 32;
Mp.insert(pair< vals, int >(g,4));
Mp.insert(pair< vals, int >(g,7));
cout<<Mp.count(g)<<endl;
cout<<Mp.size()<<endl;
return 0;
}
Now, when declare Mp as map and put false in the binary predicate..
The output is:
1
1
Mp => map && binary predicate:true ==> output: 0 2
Mp => multimap && binary predicate:true ===> output: 0 2
Mp => multimap && binary predicate:false ===> output: 2 2
I thought that the return value of predicate just tells the stl whether to put an element either infront of it or behind it. But I don't get how does this effect the size of the map itself..
Please throw some light on this. Thank you.

Your comparison must implement a strict weak ordering. This requirement is not met when you use
if(i==A.sz)
return true;
in your comparator. In this case, all the elements in the arrays the same. The functor cannot return true if both its arguments are equal. The map cannot function correctly if you do not have a strict weak ordering comparison.
You can greatly simplify your functor by using std::lexicographical_compare:
#include <algorithm> // for std::lexicographical_compare
#include <functional> // for std::greater
...
bool operator()(vals A, vals B) const
{
return std::lexicographical_compare(A, A+A.sz, B, B+B.sz); // less-than
//return std::lexicographical_compare(A, A+A.sz, B, B+B.sz, std::greater<int>()); // gt
}

Related

How to manipulate vectors in C++

I'm trying to manipulate a set of elements in vectors in c++.
vector <int> vectorOfValue;
vectorOfValue.push_back(1);
vectorOfValue.push_back(2);
vectorOfValue.push_back(3);
vectorOfValue.push_back(4);
vectorOfValue.push_back(5);
vectorOfValue.push_back(6);
vectorOfValue.push_back(7);
vectorOfValue.push_back(8);
vectorOfValue.push_back(9);
vectorOfValue.push_back(10);
I would like to know how the program can print out the vectors of values bigger 3 and smaller than 9.
It is a set of the data to exclude the outliers for example.
If you want to use the standard library algorithms and iterators, you could use std::copy_if:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
auto main(int argc, char* argv[]) -> int
{
std::vector<int> vectorOfValue;
// code for initialization of vector ..
std::copy_if(vectorOfValue.begin(),
vectorOfValue.end(),
std::ostream_iterator<int>(std::cout, "\n"),
[](const int value) { return value > 3 && value < 9; });
}
Short approach of mine using auto syntax instead of using iterator :
for(auto &i : vectorOfValue) {
if (i > 3 && i < 9) {
std::cout << i << std::endl;
}
}

Container of sets using non-default comparison predicate

I would like to create a std::map<T1, std::set<T2> > where the sets use a non-default comparator. For example, if I were declaring the set on its own, I would declare it as:
std::set<int,bool(*)(int,int)> s (fn_pt);
where fn_pt is a function pointer. In my example, when I add a new key to the std::map, I would like the set to be constructed with that non-default comparator. Is such a thing possible?
To further complicate things, my compiler does not support C++11, so I can only accept a solution that does not require C++11; however, if there is a C++11 way of doing this, I would be interested in seeing that as well.
Since you can use a functor then you should be able to use:
struct Compare
{
bool operator () (int lhs, int rhs) { return lhs - 10 < rhs; }
};
int main()
{
std::map<int, std::set<int, Compare> > data;
}
Each new set created in the map would be default constructed with the type specified in the template parameters.
Not sure why haven't you tried expanding your stub into a full example:
#include <iostream>
#include <set>
#include <map>
typedef std::set<int,bool(*)(int,int)> Set;
typedef std::map<std::string, Set> Map;
bool f(int a, int b){ return a<b;}
bool g(int a, int b){ return a>b;}
int main() {
Map m;
m["f"] = Set(&f);
m["g"] = Set(&g);
for(int i = -5; i < 5; ++i) {
m["f"].insert(i);
m["g"].insert(i);
}
for(Set::iterator i = m["f"].begin(); i != m["f"].end(); ++i){std::cout << *i << " ";}
std::cout << "\n";
for(Set::iterator i = m["g"].begin(); i != m["g"].end(); ++i){std::cout << *i << " ";}
std::cout << "\n";
return 0;
}
Output:
-5 -4 -3 -2 -1 0 1 2 3 4
4 3 2 1 0 -1 -2 -3 -4 -5
Live: http://ideone.com/D2qIHO
I see absolutely no problem in making a map of sets with custom comparers.
I might be misunderstanding the question, but you can just add keys the normal way, and construct the sets any way you want:
bool Cmp(int, int);
typedef std::set<int,bool(*)(int,int)> MySet;
typedef std::map<int, MySet> MyMap;
...
MyMap m;
m[1] = MySet(Cmp);

What is the most elegant way to check if all values in a vector<bool> are true?

This question is similar to this question:
What is the most elegant way to check if all values in a boolean array are true?
But for vector<bool> in c++.
How can use all_of for this purpose (for example I want to check the value between ranges, element 10 to 20) so I can not use begin and end.
If you want to use std::all_of, then just return the value in the predicate function :
#include <vector>
#include <iostream>
#include <algorithm>
int main()
{
std::vector< bool > v( 30, true );
const bool all = std::all_of( std::begin(v)+10, std::begin(v)+20, []( const bool v){ return v; } );
std::cout << all << std::endl;
}
I'd just try std::find(begin(v)+10, begin(v)+20, false) - it returns begin(v)+20 if all values between 10 and 20 are true.

map triple of unsigned int's to double -- is it the most optimal/efficient way?

I face the following task:
map triplet of unsigned int's to a value, which is either zero or positive (double); And be able for a given triplet obtain the double or say that it's actually zero;
I have the following simplification:
first (let's call it I) and second (let's cal it J) ints are in known ranges (from zero to IMAX and JMAX).
For the third index (K), I know an estimate of triplets (third index is scattered), say ESTIMATE;
During calculation the number of triplets growths, more precisely, for a given I and K, the number of third indices can increase.
So far I see the following solution:
keep vector of vectors of map:
vector< vector < map <unsinged int, unsigned int>>> tri_map_;
//^I ^J ^K ^index
if 'index' is not zero, obtain the value from supplementary vector:
vector< double> values;
values[index];
The whole thing to be initialized as:
tri_map_.resize(IMAX);
for (int i=0;i<IMAX;++i) tri_map_[i].resize(JMAX);
What do you think about that solution? Is there a better way to do it?
The thing I don't like is that it seems I can't do something like 'reserve' for
the map. Is there a way to try to allocate enough memory (cos I have an estimate for the third index) and check if there is enough memory for that? Apart from that I'm satisfied with it.
EDIT1:
IMAX ~ hundrets
JMAX ~ 10^5
EDIT2:
trying to incorporate the solution of sehe, but for
unordered_set and for pair;
So, that's where I have a problem specialization of ‘template<class _Tp> struct std::tr1::hash’ in different namespace :
...
EDIT3: the following works, will investigate its speed.
Thanks everyone for suggestions and advices!
#include <tr1/functional>
#include <vector>
#include <map>
#include <tr1/unordered_set>
#include <list>
#include <set>
#include <tr1/array>
#include <iostream>
struct pair_int {
unsigned int first;
unsigned int second;
bool operator< (pair_int const& o) const {
if ( first < o.first )
return true;
if ( first > o.first )
return false;
return second < o.second;
}
bool operator==(pair_int const& o) const {
return ( (first==o.first)&&(second==o.second) );
}
};
namespace std {
namespace tr1 {
template<> struct hash<pair_int> {
unsigned int operator()(pair_int const& key) const {
return ~key.first + 17u*key.second;
}
};
}
}
class pair_storage {
public:
pair_storage() {};
~pair_storage();
....
private:
pair_int pair_ij_;
std::map<pair_int,double>::iterator pairMapIterator_;
std::vector< std::map<pair_int,double> > pairMapVector_;
std::vector< std::tr1::unordered_set< pair_int > > pairMapVectorZero_;
};
Can't compile it with -std=c++0x cos I have some problems in some parts of big code...
It looks to me you are looking for
std::map
std::multimap
std::unordered_map
std::unordered_multimap
Here is a simple example of using std::unordered_multimap (which will require the specialization of std::hash<> for your key type, and is therefore the slightly more involved way to write it):
#include <tuple>
#include <unordered_map>
#include <cassert>
#include <iostream>
struct triplet
{
unsigned a,b,c;
bool operator< (triplet const& o) const { return std::tie(a,b,c) < std::tie(o.a,o.b,o.c); }
bool operator==(triplet const& o) const { return std::tie(a,b,c) ==std::tie(o.a,o.b,o.c); }
};
namespace std {
template<> struct hash<triplet> {
unsigned int operator()(triplet const& key) const {
return ~key.a + 17u*key.b + 17u*key.c; // totally made that up, could be better, I suppose
}
};
}
static std::ostream& operator<<(std::ostream& os, triplet const& key) {
return os << '[' << key.a << ',' << key.b << ',' << key.c << ']';
}
int main()
{
std::unordered_multimap<triplet, double> map;
// insert items dynamically
map.insert({ triplet{ /*I*/ 1, /*J*/ 2, /*K*/ 3 }, 0.1 } );
map.insert({ triplet{ /*I*/ 4, /*J*/ 5, /*K*/ 6 }, 0.2 } );
map.insert({ triplet{ /*I*/ 7, /*J*/ 8, /*K*/ 9 }, 0.3 } );
map.insert({ triplet{ /*I*/ 1, /*J*/ 2, /*K*/ 0 }, 0.4 } ); // duplicate (I,J) ok
map.insert({ triplet{ /*I*/ 1, /*J*/ 2, /*K*/ 0 }, 0.5 } );
assert(0 == map.count(triplet {1,5,6}));
assert(1 == map.count(triplet {4,5,6}));
auto range = map.equal_range(triplet { 1,2,0 });
for (auto it=range.first; it!=range.second; ++it)
std::cout << it->first << ": " << it->second << "\n";
}
Output (as seen on http://ideone.com/pm8Oz):
[1,2,0]: 0.4
[1,2,0]: 0.5
struct Triple
{
unsigned int A;
unsigned int B;
unsigned int C;
};
map<Triple, double> mapping;
Regarding the question "is it the most optimal/efficient way?":
Try using hash_map or unordered_map; that might be faster than map (or may be not, depending on your use case).
Regarding the question "Is there a way to try to allocate enough memory...?":
You can use unordered_map::max_load_factor to adjust memory/performance trade-off; this is just like preallocation.
Oh, and you can also use unordered_set to store elements that map to zero. That might reduce memory consumption for no performance cost.

Sorting a set<string> on the basis of length

My question is related to this.
I wanted to perform a sort() operation over the set with the help of a lambda expression as a predicate.
My code is
#include <set>
#include <string>
#include <iostream>
#include <algorithm>
int main() {
using namespace std;
string s = "abc";
set<string> results;
do {
for (int n = 1; n <= s.size(); ++n) {
results.insert(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
sort (results.begin(),results.end());[](string a, string b)->bool{
size_t alength = a.length();
size_t blength = b.length();
return (alength < blength);
});
for (set<string>::const_iterator x = results.begin(); x != results.end(); ++x) {
cout << *x << '\n';
}
return 0;
}
But the numbers and types of errors were so complex that I couldn't understand how to fix them. Can someone tell me whats wrong with this code.
Edit: Note that Steve Townsend's solution is actually the one you're searching for, as he inlines as a C++0x Lambda what I write as C++03 code below.
Another solution would be to customize the std::set ordering function:
The std::set is already ordered...
The std::set has its own ordering, and you are not supposed to change it once it is constructed. So, the following code:
int main(int argc, char* argv[])
{
std::set<std::string> aSet ;
aSet.insert("aaaaa") ;
aSet.insert("bbbbb") ;
aSet.insert("ccccccc") ;
aSet.insert("ddddddd") ;
aSet.insert("e") ;
aSet.insert("f") ;
outputSet(aSet) ;
return 0 ;
}
will output the following result:
- aaaaa
- bbbbb
- ccccccc
- ddddddd
- e
- f
... But you can customize its ordering function
Now, if you want, you can customize your set by using your own comparison function:
struct MyStringLengthCompare
{
bool operator () (const std::string & p_lhs, const std::string & p_rhs)
{
const size_t lhsLength = p_lhs.length() ;
const size_t rhsLength = p_rhs.length() ;
if(lhsLength == rhsLength)
{
return (p_lhs < p_rhs) ; // when two strings have the same
// length, defaults to the normal
// string comparison
}
return (lhsLength < rhsLength) ; // compares with the length
}
} ;
In this comparison functor, I did handle the case "same length but different content means different strings", because I believe (perhaps wrongly) that the behaviour in the original program is an error. To have the behaviour coded in the original program, please remove the if block from the code.
And now, you construct the set:
int main(int argc, char* argv[])
{
std::set<std::string, MyStringLengthCompare> aSet ;
aSet.insert("aaaaa") ;
aSet.insert("bbbbb") ;
aSet.insert("ccccccc") ;
aSet.insert("ddddddd") ;
aSet.insert("e") ;
aSet.insert("f") ;
outputSet(aSet) ;
return 0 ;
}
The set will now use the functor MyStringLengthCompare to order its items, and thus, this code will output:
- e
- f
- aaaaa
- bbbbb
- ccccccc
- ddddddd
But beware of the ordering mistake!
When you create your own ordering function, it must follow the following rule:
return true if (lhs < rhs) is true, return false otherwise
If for some reason your ordering function does not respect it, you'll have a broken set on your hands.
std::sort rearranges the elements of the sequence you give it. The arrangement of the sequence in the set is fixed, so the only iterator you can have is a const iterator.
You'll need to copy results into a vector or deque (or such) first.
vector sortable_results( results.begin(), results.end() );
You can customize the ordering of the elements in the set by providing a custom predicate to determine ordering of added elements relative to extant members. set is defined as
template <
class Key,
class Traits=less<Key>,
class Allocator=allocator<Key>
>
class set
where Traits is
The type that provides a function
object that can compare two element
values as sort keys to determine their
relative order in the set. This
argument is optional, and the binary
predicate less is the default
value.
There is background on how to use lambda expression as a template parameter here.
In your case this translates to:
auto comp = [](const string& a, const string& b) -> bool
{ return a.length() < b.length(); };
auto results = std::set <string, decltype(comp)> (comp);
Note that this will result in set elements with the same string length being treated as duplicates which is not what you want, as far as I can understand the desired outcome.
sort requires random access iterators which set doesn't provide (It is a bidirectional iterator). If you change the code to use vector it compiles fine.
You cannot sort a set. It's always ordered on keys (which are elements themselves).
To be more specific, std::sort requires random access iterators. The iterators provided by std::set are not random.
Since I wrote the original code you're using, perhaps I can expand on it... :)
struct cmp_by_length {
template<class T>
bool operator()(T const &a, T const &b) {
return a.length() < b.length() or (a.length() == b.length() and a < b);
}
};
This compares by length first, then by value. Modify the set definition:
set<string, cmp_by_length> results;
And you're good to go:
int main() {
using namespace std;
string s = "abc";
typedef set<string, cmp_by_length> Results; // convenience for below
Results results;
do {
for (int n = 1; n <= s.size(); ++n) {
results.insert(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
// would need to add cmp_by_length below, if I hadn't changed to the typedef
// i.e. set<string, cmp_by_length>::const_iterator
// but, once you start using nested types on a template, a typedef is smart
for (Results::const_iterator x = results.begin(); x != results.end(); ++x) {
cout << *x << '\n';
}
// of course, I'd rather write... ;)
//for (auto const &x : results) {
// cout << x << '\n';
//}
return 0;
}
std::set is most useful to maintain a sorted and mutating list. It faster and smaller to use a vector when the set itself wont change much once it's been built.
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
int main() {
using namespace std;
string s = "abc";
vector<string> results;
do {
for (size_t n = 1; n <= s.size(); ++n) {
results.push_back(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
//make it unique
sort( results.begin(), results.end() );
auto end_sorted = unique( results.begin(), results.end() );
results.erase( end_sorted, results.end() );
//sort by length
sort (results.begin(),results.end());
[](string lhs, string rhs)->bool
{ return lhs.length() < rhs.length(); } );
for ( const auto& result: results ) {
cout << result << '\n';
}
}
I used the classic, sort/unique/erase combo to make the results set unique.I also cleaned up your code to be a little bit more c++0x-y.