Currently I am getting the set difference of two maps and then iterating through the resulting map.
Ideally I want to create a vector of the difference instead of a map. That way I iterate more efficiently.
typedef std::map<int, Info> RegistrationMap;
RegistrationMap redundantRegs;
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::inserter(redundantRegs, redundantRegs.begin()),
[](const std::pair<int, Info> &p1, const std::pair<int, Info> &p2 {return p1.first < p2.first;});
for (auto reg : redundantRegs)
{
map2[hiu.first].Status = "delete";
}
How would you create a vector of the set difference instead? Can this be done within the set_difference function?
I'm looking for the most efficient way possible of getting the difference.
std::set_difference can write its output to any output iterator, so there is no problem with writing the output into a vector:
std::vector<std::pair<int, Info>> redundantRegs;
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::back_inserter(redundantRegs),
...);
(Note: In your comparator, change std::pair<int, Info> to std::pair<const int, Info> to avoid unnecessary copies.)
You can use std::set_difference but instead of std::inserter you better use std::back_inserter as that is most efficient on std::vector, and create std::vector accordingly:
std::vector<RegistrationMap::value_type> redundantRegs;;
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::back_inserter(redundantRegs) );
Note: in the way you wrote it you do not need to write comparator explicitly, default one will work just fine. If you do not use default one, you better get it from the std::map using std::map::value_comp() instead of writing it explicitly as sorting criteria must match for map and std::set_difference:
std::set_difference(map1.begin(), map1.end(), map2.begin(), map2.end(),
std::back_inserter(redundantRegs),
map1.value_comp() );
Live example
Related
I have references to 2 maps of type std::map<std::string, int>. I want to create a master list containing all the keys that both maps have in common. My current solution is as follows, but I am curious if there is a more efficient way of approaching this problem?
const std::map<std::string, int>& map1;
const std::map<std::string, int>& map2;
std::vector<std::string> shared_keys;
// only add to master list if both contain the string as a key
for (auto& entry : map1) {
if (map2.find(entry.first) != map2.end()) {
shared_keys.push_back(entry.first);
}
}
It would be nice if I could forgo the for loop entirely / do this as a "one-liner", but not sure how to accomplish that...
std::map is sorted, so you can just use std::set_intersection.
You'll need a custom comparator, since you're only comparing keys ... and then you need an adapter to only use the key in the output iterator ...
A one-liner is pushing it, unless you use something like the Boost.Iterator adapters. Rough sketch (untested):
template <typename K, typename V>
vector<K> map_key_intersection(map<K,V> const &a, map<K,V> const &b)
{
vector<K> result;
using Elem = typename map<K,V>::value_type;
set_intersection(a.begin(), a.end(),
b.begin(), b.end(),
boost::make_function_ouput_iterator(
[&result](Elem const &e) { result.push_back(e.first); }),
[](Elem const& a, Elem const& b) { return a.first < b.first; });
return result;
}
NB, there are several things wrong with this in practice, even apart from the fact that ranges are a better approach if you have access:
The std::map has more than two template parameters. So, add the Compare and Allocator params to your list.
What if they had different Compare types? Now we might not meet the requirements of set_intersection.
What if they have the same Compare type, but were constructed with a stateful comparator that does a different thing for each instance? Weird, but possible ... and we still don't meet the ordering constraint, but it's more expensive to check.
So, to be exactly correct, you should use eg. a.value_comp() instead of the bare operator<, but you also need to be reasonably sure that both maps use the same ordering. At least, you should add a comment to the effect that it's your client's problem if they don't.
You can use std::set_intersection, although as a one liner you will also get values from the one of the maps.
std::vector<std::pair<const std::string, int>> shared;
std::set_intersection(map1.begin(), map1.end(), map2.begin(), map2.end(), std::back_inserter(shared), map1.value_comp());
With C++20's ranges library (or a similar C++11 library), you can grab the keys for the intersection.
std::ranges::set_intersection(std::ranges::keys_view(map1), std::ranges::keys_view(map2), std::back_inserter(shared_keys));
I'd like to sort a map<pair<string, int>, int> dbg; by value using lambda :
For this I have
void test()
{
map<pair<string, int>, int> dbg;
sort( dbg.begin(), dbg.end(),
[]( pair<pair<string, int>, int>& lht, pair<pair<string, int>, int>& rht) {
return lht.second > rht.second;
});
}
But compilation failed with a lot of errors. What is the right lamda prototype here?
Sorting a map is nonsensical; it's already sorted, and you can't change the sort order after the fact by sorting it (the order can't be changed at all except by adding and removing elements, and they'll always fall into a fixed order). If you want to sort it in a different way, either:
Provide the alternate comparator to map so it's naturally sorted the way you want, or
Copy the entries to sequence type (e.g. vector) and sort that.
In this case, you want to sort by the value, which is not possible for a map, so option #2 is your only option.
This is what I am trying right now. I made a comparison function:
bool compare(const std::pair<int, Object>& left, const std::pair<int, Object>& right)
{
return (left.second.name == right.second.name) && (left.second.time == right.second.time) &&
(left.second.value == right.second.value);
}
After I add an element I call std::unique to filter duplicates:
data.push_back(std::make_pair(index, obj));
data.erase(std::unique(data.begin(), data.end(), compare), data.end());
But it seems that this doesn't work. And I don't know what the problem is.
From my understanding std::unique should use the compare predicate.
How should I update my code to make this work ?
I am using C++03.
edit:
I have tried to sort it too, but still doens't work.
bool compare2(const std::pair<int, Object>& left, const std::pair<int, Object>& right)
{
return (left.second.time< right.second.time);
}
std::sort(simulatedLatchData.begin(), simulatedLatchData.end(), compare2);
std::unique requires the range passed to it to have all the duplicate elements next to one another in order to work.
You can use std::sort on the range before you a call unique to achieve that as sorting automatically groups duplicates.
Sorting and filtering is nice, but since you never want any duplicate, why not use std::set?
And while we're at it, these pairs look suspiciously like key-values, so how about std::map?
If you want to keep only unique objects, then use an appropriate container type, such as a std::set (or std::map). For example
bool operator<(object const&, object const&);
std::set<object> data;
object obj = new_object(/*...*/);
data.insert(obj); // will only insert if unique
Suppose we have a priority queue such as:
priority_queue<pair<int, int> > pQ;
and we want pQ to be ordered so that the pair with the smallest second element is always first. Is there a simple way to accomplish this using C++11? It would be ideal if I had an elegant solution such as one that uses lambda functions. Is this possible?
You need to instantiate it with a custom comparison function, for example (namespace std assumed):
auto cmp = [](const pair<int, int>& lhs, const pair<int, int>& rhs)
{
return lhs.second < rhs.second;
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> pQ(cmp);
Yes, it's possible. std::priority_queue has a templated Compare functor that is used for sorting. You can use a lambda as the functor in c++11.
auto cmp=[](pair a,pair b){return a.second>b.second;};
priority_queue,vector>,decltype(cmp)> pq(cmp);
this is min heap of pairs by the second element in the pair.
This question already has answers here:
Sorting a vector of custom objects
(14 answers)
Closed 9 years ago.
I am trying to sort a 2D vector with the type:
vector<pair<char, double>> output;
I am trying to arrange them from the highest to lowest double value and only displaying the top 5. This is what I am trying to do:
sort(output.begin(), output.end());
But this sort is not working properly for me. What am I doing wrong?
By default, std::sort will use the less-than comparison operator for the elements of the container, which will perform am lexicographical comparison using the char first and then the double.
You can use your own ordering function/functor that orders based on the pair's double element only:
bool cmp(const std::pair<char, double>& lhs,
const std::pair<char, double>& rhs)
{
return lhs.second > rhs.second;
}
then
std::vector<std::pair<char, double>> output = ....;
sort(output.begin(), output.end(), cmp);
See working demo here.
As Violet said, you may want to include your own comparison function:
class compare
{
public:
bool operator() (std::pair<char, int> const& p1,
std::pair<char, int> const& p2) const
{
// perform logic here
}
} Predicate;
std::sort uses operator < to compare the elements, and sorts them accordingly. It has an extra optional parameter for the comparsion functor, which we can include like this:
std::sort(output.begin(), output.end(), Predicate);
Note that this can also be done using a lambda in C++11.
Is there a reason you're using a vector of pairs? In other words, does the order in which the elements are stored internally really matter to you? If not, you're probably better off using a map<double,char> with a reverse iterator to get the last 5 elements sorted by double value.
You need to write a comparison operator between the pair<char, double> operands.
http://en.cppreference.com/w/cpp/algorithm/sort