map <int, map<int, string>> DP;
if( DP.find( ? ) != DP.end() )
{
// have found
}
How to fill in (). It seem like two dimension. I know how to deal with one dimension, for example:
map<int, string> DP;
if( DP.find(1) != DP.end() )
{
// have found
}
But I don't know how to deal with two dimension.
One dimension at a time:
auto it1 = DP.find(1);
if (it1 != DP.end()) {
auto it2 = it1->find(2);
if (it2 != it1->end()) {
// found: it2->second
}
}
I think Kerrek SB`s codes exists a little problem. The way of visiting second(inner) dimension should be like this:
auto OuterIter = DP.find(1);
if (OuterIter != DP.end())
{
auto InnerMap = OuterIter->second;
auto InnerIter = InnerMap.find(0);
if (InnerIter != InnerMap.end())
{
// found the second(inner) dimension element
}
}
And you can think about chtz`s advise: You may also consider directly using std::map, std::string>
Related
I have a multimap with duplicates. When I finished the collection of the elements i would like to erase the dups.
Here is the container:
std::multimap<int, std::pair<int, bool>> container;
This following code is inside an iteration.(it is a simpler version of the original)
container.emplace(LeafId, std::make_pair(NodeId, isElectronic));
Is it good solution?
std::pair<int, std::pair<int, bool>> lastValue {-1 , {-1, -1}};
for (auto it = container.cbegin(); it != container.cend();)
{
if (it->first == lastValue.first && it->second == lastValue.second)
{
it = container.erase(it);
} else
{
lastValue = *it;
++it;
}
}
Is it good solution?
Unless you keep internal pair sorted inside multimap, no it is not a good solution as it would miss duplicates. If you can change data type then you can use:
std::map<int, std::vector<std::pair<int, bool>>>
instead of std::multimap and then for each element sort vector and remove duplicates using standard algorithms as described here Removing duplicates in a vector of strings
if you cannot I suggest to use additional std::set or std::unordered_set:
std::set<std::pair<int, bool>> tset;
int lastValue = 0;
for (auto it = container.cbegin(); it != container.cend();)
{
if( it->first != lastValue ) {
tset.clear();
lastValue = it->first;
}
if( !tset.insert( it->second ).second )
it = container.erase( it );
else
++it;
}
I have a stacked map that looks like this:
std::multimap <double, std::map<int,TypeA> > m
How can I point to the value of TypeA? I have tried:
TypeA t = m.second.second
or pointer:
for (std::multimap <double, std::map<int,StopID>>::iterator p = m.begin(); p != m.end(); p ++ ){
....
TypeA t = p->second->second
}
However, I got this error
no member named second in std::map...
Any idea?
for (std::multimap <double, std::map<int,StopID>>::iterator p = m.begin(); p != m.end(); p ++ ){
In the above you are iterating over the multimap and p->second points at the whole inner map, not a single entry in it. You need to iterate over the map too to access all entries in that.
You can use range based for-loops and structured bindings to make life easier.
for(auto& [the_double, the_map] : m) {
for(auto& [the_int, the_type_a] : the_map) {
// do what you want with the TypeA reference "the_type_a"
}
}
Edit: If I understand comments correctly, the map always contains exactly one int, TypeA pair - and in that case, just replace the map with a std::pair<int, TypeA> and you can have one loop only:
#include <utility> // std::pair
int main() {
std::multimap <double, std::pair<int, TypeA>> m;
for(auto& [the_double, the_pair] : m) {
auto& [the_int, the_type_a] = the_pair;
// do what you want with the int and TypeA references
}
}
m->second is a std::map object. You must use a loop for the next map:
using multimap_t = std::multimap <double, std::map<int, TypeA>>;
for (multimap_t::iterator p = m.begin(); p != m.end(); p++) {
std::map<int, TypeA>>& map = p->second;
for (decltype(p->second)::iterator miter = map.begin(); miter != map.end(); ++miter) {
TypeA t = miter->second;
// ...
}
}
A simpler version with auto (C++11):
for (auto p = m.begin(); p != m.end(); p++) {
auto& map = p->second;
for (auto miter = map.begin(); miter != map.end(); ++miter) {
TypeA t = miter->second;
// ...
}
}
How to iterate through a std::map<string,int> and std::vector<int> using single for loop ?
I have seen this questions but could not solve my problem.
I am trying like this
map<string,int> data;
data["Shravan"] = 1;
data["Mama"] = 2;
data["Sa1"] = 3;
data["Jhandu"] = 4;
vector<int> values = {1,2,3,4};
for(const auto& it1: data,it2 : values) {
// Do something
}
Edit : I can not go through one by one. Because i am using the key of std::map and value of std::vector in the same function. Which will be called inside for loop.
Both the container of same size.
If you know there's both the same length, use something like:
auto vit = begin(value);
auto mit = begin(data);
for (; vit != end(value); ++mit, ++vit) {
// Use mit and vit
}
How about a do-while? Provided that your containers aren't empty.
auto iv = std::begin(value);
auto id = std::begin(data);
do {
// Use those iterators
} while(++iv != std::end(value) && ++id != std::end(data))
Or use while if you'd like to handle empty containers too.
auto iv = std::begin(value);
auto id = std::begin(data);
while(iv != std::end(value) && id != std::end(data)) {
// Use those iterators
iv++; id++;
}
Consider boost::zip_iterator discussed in this answer https://stackoverflow.com/a/8513803/2210478
You can iterate over both the map and the vector and make sure to check the iterators against the end of the corresponding container.
auto map_iter = data.begin();
auto vec_iter = value.begin();
for (; map_iter != data.end() && vec_iter != value.end();
++map_iter, ++vec_iter) {
// Use map_iter and vec_iter
}
ALL,
std::map<int, std::string> addressee;
std::map<int, std::string>::iterator it1, it2;
for( it1 = addressee.begin(); it1 != addressee().end(); it1++ )
{
bool found = false;
for( it2 = it1 + 1; it2 != addressee.end() && !found; it2++ )
{
if( it1->second == it1->second )
{
printf( "Multiple occurences of addressees found" );
found = true;
}
}
}
gcc spits out an error: no match for operator+.
This code is a simplified version of what I'm trying to do right now. I guess I can use std::advance(), but it seems it just going to be a waste of the function call.
Is there a better fix for that?
std::map does not have random access iterators, only bidirectional iterators, so there's no + n operation. Instead, use std::next:
#include <iterator>
#include <map>
// ...
for (auto it1 = addressee.begin(), e = addressee.end(); it1 != e; ++it1)
{
for (auto it2 = std::next(it1); it2 != e; ++it2)
{
if (it1->second == it2->second)
{
// ...
break;
}
}
}
In fact, you should always use std::next, since it knows which iterator category its argument has and what the most efficient way to compute the next iterator is. That way, you don't have to care about the specific container you happen to be using.
#Kerrek has already pointed out how to handle the problem you're having at the syntactic level.
I'm going to consider the problem at a more algorithmic level--what you're really trying to accomplish overall, rather than just looking at how to repair that particular line of the code.
Unless the collection involved is dependably tiny so the efficiency of this operation doesn't matter at all, I'd make a copy of the mapped values from the collection, then use sort and unique on it to see if there are any duplicates:
std::vector<std::string> temp;
std::transform(addressee.begin(), addressee.end(),
std::back_inserter(temp),
[](std::pair<int, std::string> const &in) { return in.second; });
std::sort(temp.begin(), temp.end());
if (std::unique(temp.begin(), temp.end()) != temp.end()) {
std::cout << "Multiple occurrences of addressees found";
found = true;
}
This reduces the complexity from O(N2) to O(N log N), which will typically be quite substantial if the collection is large at all.
Check if map in C++ contains all the keys from another map answers my question but I'm not sure how we iterate through two maps at the same time.
I know how to iterate through one as shown:
typedef std::map<QString, PropertyData> TagData;
TagData original = readFileToMap("FoxHud.bak");
for (TagData::const_iterator tagIterator = original.begin(); tagIterator != original.end(); tagIterator++) {
}
Try this way:
// As std::map keys are sorted, we can do:
typedef std::map<string, int> TagData;
TagData map1;
TagData map2;
...
TagData::const_iterator map1It = map1.begin();
TagData::const_iterator map2It = map2.begin();
bool ok = true;
std::size_t cnt = 0;
while (map2It != map2.end() && map1It != map1.end()) {
if (map1It->first != map2It->first) {
map1It++;
} else {
map2It++;
cnt++;
}
}
if (cnt != map2.size()) ok = false;
cout << "OK = " << ok << endl;
This should work with maps that are not the same size, as well.
If you want to iterate the 2 maps simultaneously, you can do this:
if (map1.size() != map2.size())
; // problem
else
{
for (map<X,Y>::const_iterator it1 = map1.begin(),
it2 = map2.begin();
it1 != map1.end() && it2 != map2.end();
++it1 , ++it2)
{
// ...
}
}
Now if you want to iterate through the 2 maps at different "speeds", then a while loop to condition the increments of it1 and it2 independently would then be more appropriate. See Golgauth's answer for an example.