how to copy elements from a map to a std:: string - c++

I am writing a program that implements a uni-directional graph using std::map. I have to search for the key and then copy the vector values corresponding to that key into a new location in the map. The problem is that the key I search for is extracted from yet another location in the map. I understand why I am getting the error as std::copy_n does not copy from vector to string (although it works the other way) but I don't know how to fix this.
I am copying a snippet of the code below:
The keys to search for are stored in a vector corresponding to key mykey.
for (
vector<string>::iterator itr = mymap.find(mykey)->second.begin()
; itr != mymap.find(mykey)->second.end()
; itr++
)
{
string find_key = "";
// error C2664 :cannot convert parameter 1 from 'std::_Vector_iterator<_Myvec>'
// to 'const std::basic_string<_Elem,_Traits,_Ax> &'
std::copy_n(itr, 1, find_key.begin());
if (mymap.find(find_key) == mymap.end())
cout << "key not found" << endl;
else
mymap[mykey].insert(
mymap.find(find_key)->second.begin()
, mymap.find(find_key)->second.end()
);
}
Edit: using stringstream to extract key from map
for (vector::iterator itr =mymap.find(mykey)->second.begin(); itr!=mymap.find(mykey)->second.end();++itr){
stringstream ss;
ss<< *itr;
string find_key = ss.str();
if (mymap.find(find_key)==mymap.end())
cout<<"key not found"<<endl;
else
for (vector<string>::iterator mapit= mymap.find(find_key)->second.begin(); mapit!=mymap.find(find_key)->second.end(); ++mapit)
mymap[mykey].push_back(*mapit);}
}
I am now getting a "vector not incrementable" error. Can you please tell me why?Also, what happens to duplicate values in a map? Thanks a lot for your help!

copy_n with a size one copy only one element (of course), but you're mixing an input iterator on string and an output iterator on char.
So do you want to read the first character of the current string or the whole string? I guess the second makes more sense in your context. So you could simple deference the iterator:
string const& find_key = *itr;
Regarding performance, even though I do not recommend to look into optimizations too earlier in the development of your software, here you perform some searches way too many times.
For example, in the first loop, at every iteration you'll look for mykey in your map. You could rewrite it using C++11 features:
for (auto const& str : mymap.find(mykey)->second)
This will call find once only and iterate on the (assuming to be existing) associated vector of string.
Here I guess that str is what you called find_key in your original post.
Then again you call three times mymap.find(find_key). That can be optimized quite easily. Additionally, does the insert compile? I couldn't find a matching function in the doc...
auto it = mymap.find(find_key);
if (it == mymap.end()) {
cout << "key not found" << endl;
} else {
auto const& vec = *it; // a ref to vector of strings to be copied
auto& dest = mymap[mykey];
dest.insert(std::end(dest), std::begin(vec), std::end(vec));
}
And when we put everything together we get:
for (auto const& find_key : mymap.find(mykey)->second) {
auto it = mymap.find(find_key);
if (it == mymap.end()) {
std::cout << "key not found" << std::endl;
} else {
auto const& vec = *it; // a ref to vector of strings to be copied
auto& dest = mymap[mykey];
dest.insert(std::end(dest), std::begin(vec), std::end(vec));
}
}
Doesn't that make more sense? ;-)

Related

How to add the results from the iteration to new multimap in c++?

How to insert result into a new multimap?? I am trying to search over dictionary container to find keyword given by the user and I need to iterate over the tempCollector to find distinct elements. But, I can't seem to find a way to store the results in tempCollector.
//current container with all the data
multimap<string, DictionaryItem> dictionaryContainer;
void search(vector<string> input) {
if (dictionaryContainer.empty()) {
cout << "it's empty";
}
int inputSize = input.size();
string tempKeyword = input[0];
//need to copy or insert the value and keys to the tempCollector
multimap<string, DictionaryItem>tempCollector;
//iteration to find keyword; want to store the result in tempCollector
auto its = dictionaryContainer.equal_range(tempKeyword);
for (multimap<string, DictionaryItem>::iterator itr =its.first; itr != its.second; itr++) {
itr->second.print();
}
};
If you want to copy the whole its range:
tempCollector.insert(its.first, its.second);
If you want to copy each element:
for (auto itr =its.first; itr != its.second; itr++) {
if (condition) {
tempCollector.emplace(tempKeyword, itr->second);
//or
tempCollector.insert(*itr);
//or
tempCollector.emplace(tempKeyWord, DictionaryItem(...));
}
}
Keep in mind (multi)map handles pairs of key/values as std::pair<Key,T> (aka value_type).
The multimap::insert method assumes you've already constructed the pair(s) to insert, while multimap::emplace will build them for you.

Comparing 2 std::lists of std::pairs

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;
}

operation on 2 dimensional hash map C++

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>

Dereferencing iterator to pointers correctly

I have a vector of pointers to objects. Each object stores a value and has a toString() function that returns that value as a string. I have an iterator to go through the vector and I need to extract the value of each object by calling toString(). The problem is, I can't figure out how to get the value.
This function is ultimately supposed to write the number to a file, but I'm using the cout for testing.
void writeNumbers(vector<Integer*>& input)
{
ofstream write;
write.open("Integers.txt");
vector<Integer*>::iterator iter = input.begin();
for (iter; iter < input.end(); iter++)
{
**std::cout << (*iter)->toString() << std::endl;**
}
write.close();
I get an Access Violation error which points me to the toString() function:
std::string Integer::toString()
{
std::stringstream ss;
ss << *(this)->value;
return ss.str();
}
toString() works fine whenever I don't try to access it through the iterator.
Edit: Value in toString is actually a pointer to a number.
Edit2: New writeNumbers:
void writeNumbers(vector<Integer*>& input)
{
ofstream write;
write.open("Integers.txt");
vector<Integer*>::iterator iter = input.begin();
for (iter; iter != input.end(); iter++)
{
std::cout << (*iter)->toString() << std::endl;
}
write.close();
}
Final Edit: Alright, the problem turned out to be a borked constructor that was failing to initialize a pointer properly, so I was WAY off base on where the problem actually was. :)
Integer::Integer(string input)
{
if(isNaN(input))
value = new int(atoi(input.c_str()));
}
So it should have been !isNaN, plus I fixed the problem of initializing it on bad input:
//New constructor, works 100%
Integer::Integer(string input)
{
if(!isNaN(input))
value = new int(atoi(input.c_str()));
else
value = new int(0);
}
Your toSting() has the issue. Change
ss <<*(this)->value;
to
ss << value;
EDIT: This is not an error, but a general advice when using iterators. Dont use < to check for end, use !=.
iter < input.end()
It should be like this:
iter != input.end()
This is because for certain containers, the < operator will not do what you expect. As a result, at some point you could be dereferencing input.end() itself, which points at nothing.

c++ hash_multimap how to get the values

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.