This is probably really simple, but I can't find a simple example for it.
I understand that with a hash_multimap you can have several values mapped to a single key. But how exactly would I access those values. All the examples I stumbled across always just access the first value mapped to the the key. Heres an example of what I mean
key : value
1 : obj1a;
2 : obj2a, obj2b, obj2c
how would I access obj2b and obj2c, not just obj2a
The usual multimap iteration loop is like this:
#include <unordered_multimap>
typedef std::unordered_multimap<K, V> mmap_t;
mmap_t m;
for (mmap_t::const_iterator it1 = m.begin(), it2 = it1, end = m.end(); it1 != end; it1 = it2)
{
// outer loop over unique keys
for ( ; it1->first == it2->first; ++it2)
{
// inner loop, all keys equal to it1->first
}
}
To iterate over just one key value, use equal_range instead.
std::pair<mmap_t::const_iterator, mmap_t::const_iterator> p = m.equal_range(key);
for (mmap_t::const_iterator it = p.first; it != p.second; ++it)
{
// use "it->second"
}
For example, equal_range returns an two iterators, to the begin and end of the matching range :
void lookup(const map_type& Map, int key)
{
cout << key << ": ";
pair<map_type::const_iterator, map_type::const_iterator> p =
Map.equal_range(key);
for (map_type::const_iterator i = p.first; i != p.second; ++i)
cout << (*i).second << " ";
cout << endl;
}
where we're using a map_type like
class ObjectT; // This is the type of object you want to store
typedef hash_multimap<int, ObjectT> map_type;
Just grab an iterator to the first one and increment it. If the keys are still equal, you've got another entry with the same key value. You can also use equal_range.
Related
I need to iterate through the keys of a map, but looking ahead to future keys. For example:
map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
cout << it->first << "\n";
//is the next element equal to 3?
auto next = it++;
std::cout << "equals 3" << next==3 << std::endl
}
but sometimes I don't want to see the next element (n+1), maybe I want to see the n+10 element, etc. How do I do this? If my list has 100 elements, and I arrive at element 99, then 99+10 is gonna break evrything. Is there a way to test if my iterator can achieve n+10?
The best solution I thougth of is to keep track of an index i and see if I can call it + 10 (that is, if i+10<mapSize). Bus is there a more elegant way? Maybe testing if the n+10 iterator exists or something?
Map does not sound like the appropiate data type for your use case. Try switching to a container that supports random access
I think that your are looking for something like std::advance (Please see here), but with an additional check, if the advance operation was past the end or not.
We can use a small lambda to do this kind of check. Since it uses only an increment operation, it should work for all type of containers.
Please see the following example to illustrate the function:
#include <iostream>
#include <map>
#include <iterator>
using Type = std::map<int, int>;
using TypeIter = Type::iterator;
int main() {
// Lambda to advance a container iterator and check, if that was possible
auto advanceAndCheck = [](const Type& t, const TypeIter& ti, size_t advance) -> std::pair<bool, TypeIter>
{ TypeIter i{ ti }; while ((i != t.end()) && (advance--)) ++i; return { i != t.end(), i }; };
// Test data
Type m{ {1,1}, {2,2}, {3,3}, {4,4}, {5,5} , {6,6} };
// Iterate over container
for (TypeIter it = m.begin(); it != m.end(); ++it) {
// Show some values
std::cout << it->first << "\n";
// Test
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 1);
if (OK && itn->first == 3) std::cout << "The next Element is 3\n";
}
{
// Advance and check
auto [OK, itn] = advanceAndCheck(m, it, 5);
if (OK && itn->first == 6) std::cout << "The 5th next Element is 6\n";
}
}
}
I am hoping you can help me out here. I have searched for other answers, but I havent found something that matches my specific situation (but if you do find one, please let me know the URL!). I have seen a lot of suggestions about using std::map instead of list and I dont mind switching the container if need be.
Currently, I have two Lists of pairs i.e.
std:list <std::pair<string,string>> outputList1;
std:list <std::pair<string,string>> outputList2;
I have populated each list with User Settings that I have retrieved from an SQL database (I omit the SQL retrieval code here).
Example list:
outputList1 (first, second)
CanSeeAll, True
CanSubmit, False
CanControl, False
OutputList2:
CanSeeAll, False
CanSubmit, True
CanControl, False
I want to iterate through both lists and find the mismatches. For example, find the first string of the first pair of the first list to find the matching first string in the second list, then compare the second string to determine whether they match, then print out the non matching pairs to a new string (eventually to file), and so on.
In this example, the final string would have CanSeeAll and CanSubmit as the final output since those are the two that mismatch.
Here is what I've tried so far, but I get a blank string:
std::list <std::pair<std::string,std::string>>::iterator it1 = outputList1.begin();
std::list <std::pair<std::string,std::string>>::iterator it2 = outputList2.begin();
string token;
while (it1 != outputList1.end()){
if((*it1).first == ((*it2).first))
{
if((*it1).second != ((*it2).second))
{
token.append((*it1).first);
token.append(",");
token.append((*it1).second);
token.append("\r\n");
}
it1++;
it2 = outputList2.begin();
}
it2++;
if (it2 == outputList2.end())
it1++;
}
I know this logic is flawed as it will skip the first pair on the second list after the first iteration, but this is the best I can come up with at the moment, and I am banging my head on the keyboard a the moment.
Thanks everyone!
As I understand the problem,
you want to compare every element of one list, to every other element of another list.
You could use a pair of nested range based for loops.
#include <list>
#include <string>
int main(){
std::list<std::pair<std::string,std::string>> l1;
std::list<std::pair<std::string,std::string>> l2;
for (auto x: l1){
for (auto y: l2){
//compare x to y
}
}
}
The answer uses an auxiliary map but, have in mind you will get better result if you use two maps (or hash tables) instead of two list.
// create a map for elements in l2
std::map<std::string, std::string> l2map;
// move elements from l2 to the map so we get O(N*log(N)) instead of O(n²)
for (std::list<std::pair<std::string,std::string> >::iterator it = l2.begin();
it != l2.end();
++it)
{
l2map.insert(*it);
}
// walk l1 and look in l2map
for (std::list<std::pair<std::string,std::string> >::iterator l1it = l1.begin();
l1it != l1.end();
++l1it)
{
// look for the element with the same key in l2
// l1it->first is the key form l1
std::map<std::string, std::string>::iterator l2it = l2map.find(l1it->first);
if (l2it != l2map.end()) {
// found, then compare
if (l1it->second != l2it->second) { // l1it->second is the value from l1
// mismatch
}
} else {
// not in l2
}
}
You could use std::mismatch with the pre-condition: all settings occur in the same order in both lists (you could do a sort if this is not the case)
auto iterPair = std::mismatch(l1.begin(), l1.end(), l2.begin());
while (iterPair.first != l1.end()) {
// TODO: Handle the mismatching iterators
iterPair = std::mismatch(iterPair.first + 1, l1.end(), iterPair.second + 1);
}
If the keys in your lists come in the same order, as in your example, you can traverse the lists linearly:
std::ostringstream s;
std:list<std::pair<string, string>>::const_iterator i2(outputList2.cbegin());
for(auto const &pair: outputList1) {
if(pair.second != i2->second) {
s << pair.first << ": " << pair.second << " != " << i2->second << endl;
}
++i2;
}
Alternatively, use STL algorithms:
#include <algorithm>
typedef std::list<std::pair<std::string, std::string>> List;
std::ostringstream s;
for(
auto itrs(
std::mismatch(
outputList1.cbegin(), outputList1.cend(), outputList2.cbegin()
, [](auto const &l, auto const &r){ return l.second == r.second; }))
; itrs.first != outputList1.cend()
; itrs = std::mismatch(itrs.first, outputList1.cend(), itrs.second
, [](auto const &l, auto const &r){ return l.second == r.second; }))
{
s << itrs.first->first << ": "
<< itrs.first->second << " != " << itrs.second->second
<< std::endl;
}
I am currently working on a coding question:
Given an array of strings, return all groups of strings that are anagrams.
For example, Given:
{asch, scah, bva, vba, soa}
return
{ {asch, scah}, {bva, vba}, {soa}}
To solve this question less than O(n^2) time, we should firstly sort each word, and group the sorted words in one set, if the sorted words are the same.
I wanted to use two-dimensional hashmap.
map<string, map<int,string>> container;
to use this two-dimensional hashmap, the first key is the sorted word, the second key is its index in the original sequence, and the value is the original word.
for(int i=0; i<sequence.size();i++)
{
string original_word = sequence[i];
string sorted_word = original_word;
sort(sorted_word.begin(),sorted_word.end());
container[sorted_word][i] = original_word;
}
After this loop, I believe all the anagrams which must have the same sorted_word, will be grouped into the first level of hashmap.
My question is, how should I write the code in order to get the set which has the same sorted_word?
Can I do
for( iterator itr = container.begin(); itr != container.end(); itr++)
{
auto grouped_words = itr.second(); // what is the data type of grouped_word here?
}
correct me if there is anything wrong. Thanks.
I think there's a mistake here:
vector<string, vector<int,string>> container; // ???
As in your question you speak about hash maps, I suppose that you meant:
unordered_map<string, unordered_map<int,string>> container;
In this case, you can use the result as follows:
for( auto itr = container.begin(); itr != container.end(); itr++)
{
auto &grouped_words = itr->second; // prefer a reference
cout << itr->first<<": ";
for (auto &x : grouped_words) {
cout << "\t" << x.first << ":"<< x.second<<endl;
}
}
Here a live demo.
Edit: grouped_words is (here) a reference to an unordered_map<int, string>
I have a vector of maps containing strings .,i.e,
vector< map <string,string> > vectorOfMaps;
vector< map <string,string> >::const_iterator itr =vectorOfMaps.begin();
vectorOfMaps is filled in another function and the caller function can access only the const_iterator itr.
How do i access the key and its respective value of each map element in the vectorOfMaps?
Any help appreciated:)
EDIT: Got my solution.
map<string,string> myMap = (*itrVectorOfMaps);
while(loop till the end element)
{
for(map<string,string>::iterator itM = myMap.begin();
itM != myMap.end(); itM++)
{
cout<<"Key="<<itM->first<<" => Value="<<itM->second<<endl;
}
itrVectorOfMaps++;
myMap=(*itrVectorOfMaps);
}
You can use the first and second keywords to access the map elements as you're iterating over the vector of maps.
for(auto const& currentMap : vectorOfMaps) // Loop over all the maps
{
for(auto const& element : currentMap) // Loop over elements of current map
{
std::string const& key = element.first;
std::string const& value = element.second;
}
}
Your solution is bad because you make multiple copies of maps, first one just before the loop and then inside the loop. Consider this shorter and faster version:
for (auto const& el: *itrVectorOfMaps)
cout << "Key=" << el.first << " => Value=" << el.second << endl;
For example I have a map like this:
map<string , map <int , int>> example;
and an iterator:
map<string , map <int, int>>::iterator iter;
string word;
And i want to access to the inner map :
for(iter = example.begin();iter!=example.end;iter++){
iter = Map.find(word);
iter -> second //
}
What i should do to access the inner map just for example if iter->second ==4 -it's is not correct ,
or can i do (iter->second)->second ??? can u give me an advise. i undestand that iterator is giving me a pair of (int,int) so i tryed to do another iterator map ::iterator i; and to assing iter->second = i, but it didin't help me to;
For complex types use typedef it will make your life much easier:
typedef std::map< int, int > Ints;
typedef std::map< std::string, Ints > String2Ints;
String2Ints example;
std::string word;
String2Ints::iterator it = example.find( word );
if( it != example.end() ) {
Ints &innerMap = it->second;
Ints::iterator innerit = innerMap.find( 4 );
if( innerit != innerMap.end() )
std::cout << "found value for word " << word << " 4 - " << innerit->second << std::endl;
}
Also your loop and find inside is incorrect, you should either iterate over map or search for value by find(), what you do in your code does not make any sense (technically infinite loop if word is found)
iter->second is a map, so if you want to find something in it you need another find.
You can also use your iterator directly, without the for loop.
Ex:
map<string , map <int, int>>::iterator iter;
iter = example.find(word);
if (iter != example.end()){
map<int, int>>::iterator innerIter;
int key = 4;
innerIter = iter->second.find(key);
if (innerIter != iter->second.end()){
(...)
}
}