This question already has answers here:
Closed 12 years ago.
Possible Duplicates:
Checking value exist in a std::map - C++
How to traverse a stl map/vector/list/etc?
Hello,
Is it possible to search for specific value in std::map, not knowing the key? I know I could iterate over whole map, and compare values, but it is possible to do using a function from std algorithms?
Well, you could use std::find_if :
int main()
{
typedef std::map<int, std::string> my_map;
my_map m;
m.insert(std::make_pair(0, "zero"));
m.insert(std::make_pair(1, "one"));
m.insert(std::make_pair(2, "two"));
const std::string s("one");
const my_map::const_iterator it = std::find_if(
m.begin(), m.end(), boost::bind(&my_map::value_type::second, _1) == s
);
}
But that's just slightly better than a hand-crafted loop : it's still O(n).
You could use Boost.Bimap if you want to index on values as well as keys. Without this or similar, this will have to be done by brute force (=> scan the map by hand).
Boost.Bimap is a bidirectional maps
library for C++. With Boost.Bimap you
can create associative containers in
which both types can be used as key.
Will this help? STL find_if
You need to have some sort of predicate, either a function pointer or an object with operator() implemented. Said predicate should take just one parameter.
There are (awkward) ways to do this using standard functions (e.g., std::find_if), but these still involve iterating over the whole map. Boost.Bimap will provide efficient indexing in both directions, and you can go even further with Boost.Multi-Index.
Related
Right now I have a map and I need to sort it by value(int), and then by key(string) if there is a tie. I know I would need to write a customized comparison function for this, however so far I haven't been able to make it work.
(I need to store my stuffs in a map since the strings are words and ints are the frequencies and I will need to 'find' the pairs by searching the keys later)
The std::map can only be sorted by key (string in your case).
If you need to sort it by value as well, you'd need to create a std::multimap with the int as key and the string as value, and populate it by iterating over the map.
Alternatively, you could also create a vector<pair<int,string>> that you populate by iteration over the map and just use std::sort().
You can use a std::multiset<std::pair<int, std::string>>
With the information given, it's a bit of a guessing game, but unless you are shuffling massive amounts of data, this may do.
using entry = std::pair<std::string, int>;
using CompareFunc = bool(*)(const entry&, const entry&);
using sortset = std::set<entry, CompareFunc>;
sortset bv(themap.begin(), themap.end(), [](auto& a, auto&b){ a.second!=b.second?a.second<b.second:a.first<b.first; });
for(const auto& d : bv) {
//
}
I have question with Boost::bimap and could not find answer from boost document.
using AToBBimap = boost::bimap< boost::bimaps::unordered_set_of<CString>, boost::bimaps::multiset_of<CString> >; //hashed bimap
using AToBBimapValueT = AToBBimap ::value_type;
AToBBimap bi_map;
bi_map.insert(AToBBimapValueT{"message1", "value"});
bi_map.insert(AToBBimapValueT{"message2", "value"});
bi_map.right.find("value");
QUESTION: with bi_map.right.find("value") looks like can only get iterator to {"message1", "value"}, is there possible to get a list of both matching like [{"message1", "value"}, {"message2", "value"}]?
The answer is equal_range("value"), like with std::multiset and std::multimap.
That member returns a pair of iterators, which is conveniently compatible with Boost's iterator-range factory, so you can use it:
for (auto p : boost::make_iterator_range(bi_map.right.equal_range("value")))
do something with p.second;
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ Delete Duplicate Entries in a vector
I need to delete double entries in C++ STL vectors. An important point is that the order of elements in the resulting vector must be equivalent to the order in the input vector. Is there an algorithm (e.g. in stl, boost) which would do this?
There are two possible cases here: either the vector is already sorted or it isn't.
If it is, std::erase and std::unique can easily solve this as shown in the other answers.
If it isn't then you can do achieve the goal with
v.erase(std::remove_if(v.begin(), v.end(), predicate), v.end());
but there's a problem in that predicate is not trivial to specify: it's a function that accepts one argument (the value to consider) and it needs to answer the question "is there any equal value earlier in the vector?". Since you aren't told where exactly in the vector the supplied argument is, that means you 'd have to keep quite a bit of manual state to be able to answer this.
A convenient option here would be to use an std::set to do some of the heavy lifting:
std::set<decltype(v)::value_type> set(v.begin(), v.end());
v.erase(
std::remove_if(
v.begin(),
v.end(),
[&set] (decltype(v)::value_type item) { return !set.erase(item); }),
v.end());
What this does is prepopulate an std::set with the values in the vector and then check if an item has been seen before by seeing if it has been removed from the set. This way the result will retain only the first item from each set of items that compare equal in the input.
See it in action.
If your vector is not sorted and you thus cannot just use std::unique (and likewise cannot sort it which would destroy your order), you can use something like this function (using C++11 lambdas):
template<typename FwdIt> FwdIt unordered_unique(FwdIt first, FwdIt last)
{
typedef typename std::iterator_traits<FwdIt>::value_type value_type;
std::set<value_type> unique;
return std::remove_if(first, last, [&unique](const value_type &arg) {
return !unique.insert(arg).second; });
}
Which can be invoke using the usual erase-romve-idiom:
v.erase(unordered_unique(v.begin(), v.end()), v.end());
Of course you can also use C++11's std::unordered_set instead of a std::set (for hashable types, of course) to get away from O(n log n) in average case.
How about std::unique?
auto firstDup = std::unique(myvector.begin(), myvector.end());
Use next:
vec.erase( unique( vec.begin(), vec.end() ), vec.end() );
This question already has answers here:
How to find out if an item is present in a std::vector?
(18 answers)
Closed 10 years ago.
Is there any built in function which tells me that my vector contains a certain element or not
e.g.
std::vector<string> v;
v.push_back("abc");
v.push_back("xyz");
if (v.contains("abc")) // I am looking for one such feature, is there any
// such function or i need to loop through whole vector?
You can use std::find as follows:
if (std::find(v.begin(), v.end(), "abc") != v.end())
{
// Element in vector.
}
To be able to use std::find: include <algorithm>.
If your container only contains unique values, consider using std::set instead. It allows querying of set membership with logarithmic complexity.
std::set<std::string> s;
s.insert("abc");
s.insert("xyz");
if (s.find("abc") != s.end()) { ...
If your vector is kept sorted, use std::binary_search, it offers logarithmic complexity as well.
If all else fails, fall back to std::find, which is a simple linear search.
In C++11, you can use std::any_of instead.
An example to find if there is any zero in the array:
std::array<int,3> foo = {0,1,-1};
if ( std::any_of(foo.begin(), foo.end(), [](int i){return i==0;}) )
std::cout << "zero found...";
it's in <algorithm> and called std::find.
std::find().
I have this small program that reads a line of input & prints the words in it, with their respective number of occurrences. I want to sort the elements in the map that stores these values according to their occurrences. I mean, the words that only appear once, will be ordered to be at the beginning, then the words that appeared twice 7 so on. I know that the predicate should return a bool value, but I don't know what the parameters should be. Should it be two iterators to the map? If some one could explain this, it would be greatly appreciated. Thank you in advance.
#include<iostream>
#include<map>
using std::cout;
using std::cin;
using std::endl;
using std::string;
using std::map;
int main()
{
string s;
map<string,int> counters; //store each word & an associated counter
//read the input, keeping track of each word & how often we see it
while(cin>>s)
{
++counters[s];
}
//write the words & associated counts
for(map<string,int>::const_iterator iter = counters.begin();iter != counters.end();iter++)
{
cout<<iter->first<<"\t"<<iter->second<<endl;
}
return 0;
}
std::map is always sorted according to its key. You cannot sort the elements by their value.
You need to copy the contents to another data structure (for example std::vector<std::pair<string, int> >) which can be sorted.
Here is a predicate that can be used to sort such a vector. Note that sorting algorithms in C++ standard library need a "less than" predicate which basically says "is a smaller than b".
bool cmp(std::pair<string, int> const &a, std::pair<string, int> const &b) {
return a.second < b.second;
}
You can't resort a map, it's order is predefined (by default, from std::less on the key type). The easiest solution for your problem would be to create a std::multimap<int, string> and insert your values there, then just loop over the multimap, which will be ordered on the key type (int, the number of occurences), which will give you the order that you want, without having to define a predicate.
You are not going to be able to do this with one pass with an std::map. It can only be sorted on one thing at a time, and you cannot change the key in-place. What I would recommend is to use the code you have now to maintain the counters map, then use std::max_element with a comparison function that compares the second field of each std::pair<string, int> in the map.
A map has its keys sorted, not its values. That's what makes the map efficent. You cannot sort it by occurrences without using another data structure (maybe a reversed index!)
As stated, it simply won't work -- a map always remains sorted by its key value, which would be the strings.
As others have noted, you can copy the data to some other structure, and sort by the value. Another possibility would be to use a Boost bimap instead. I've posted a demo of the basic idea previously.
You probably want to transform map<string,int> to vector<pair<const string, int> > then sort the vector on the int member.
You could do
struct PairLessSecond
{
template< typename P >
bool operator()( const P& pairLeft, const P& pairRight ) const
{
return pairLeft.second < pairRight.second;
}
};
You can probably also construct all this somehow using a lambda with a bind.
Now
std::vector< std::map<std::string,int>::value_type > byCount;
std::sort( byCount.begin(), byCount.end(), PairLessSecond() );