I have a multimap:
std::multimap < string, string >::iterator iter_map;
multimap < string, set<string> > my.map;
Typical output and data structure:
key - value
bird - air
bird - earth
fish - water
lion - earth
lion - water
I would like change the data structure (no only print to) such that that the new data
would be:
bird - air, earth
fish - water
lion - earth, water
In other way, how to eliminate the duplicate keys?
I did this:
int size_mmap = namesMultiMap1.size();
pair<multimap<string,string>::iterator,multimap<string,string>::iterator> ret;
for (int i = 0; i < 1; i++){
cout << " xxx "<< " =>";
ret = namesMultiMap1.equal_range("xxx");
for (nameItr1=ret.first; nameItr1!=ret.second; ++nameItr1)
cout << " " << (*nameItr1).second;
}
In this way I print the values associeted at a key xxx but I print a element at once.
I would like to print all keys and values. I need automated this because the map is big.
If I iterate using a iterator for namesMultiMap1 a print the repeat keys.
Ok, this can be done like follows. Notice, that the type of the result is map<string, set<string> >, not multimap < string, set<string> > as you wanted, cause you don't want duplicated keys in it, so map makes more sense.
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <iterator>
using namespace std;
typedef multimap<string,string> mm;
typedef map<string, set<string> > ms;
ms convert(const mm& m)
{
ms r;
for (mm::const_iterator it = m.begin(); it != m.end(); ++it)
{
set<string>& s(r[it->first]);
s.insert(it->second);
}
return r;
}
int main()
{
mm m;
m.insert(make_pair("john", "kowalski"));
m.insert(make_pair("john", "smiths"));
m.insert(make_pair("mary", "doe"));
m.insert(make_pair("mary", "walker"));
ms s(convert(m));
for (ms::iterator it = s.begin(); it != s.end(); ++it)
{
cout << it->first << ": ";
set<string> &st(it->second);
copy(st.begin(), st.end(), ostream_iterator<string>(cout, ", "));
cout << endl;
}
return 0;
}
This will print:
john: kowalski, smiths,
mary: doe, walker,
Related
So i have Text.txt where are countries and rivers.So i have to output river and all countries where that current river exists.
Text.txt :
Spanish Taho
France Rhine
Ukrain Dnipro
Germany Rhine
Russia Dnipro
Portugal Taho
Code:
#include <iostream>
#include <map>
#include <string>
#include <fstream>
using namespace std;
int main()
{
map<string, string> country;
ifstream in("Text.txt");
string key;
string river;
while (in >> key >> river)
{
country[key] = river;
}
map<string, string>::iterator it;
map<string, string>::iterator it2;
for (it = country.begin(); it != country.end(); it++) {
cout << it->second << ":" << endl;
for (it2 = country.begin(); it2 != country.end(); ++it2) {
if (it->second == it2->second ) {
cout << "-" << it2->first << endl;
}
}
}
cout << endl;
system("pause");
return 0;
}
Result:
Rhine:
-France
-Germany
Rhine:
-France
-Germany
Taho:
-Portugal
-Spanish
Dnipro:
-Russia
-Ukrain
Taho:
-Portugal
-Spanish
Dnipro:
-Russia
-Ukrain
What I need:
Rhine:
-France
-Germany
Taho:
-Portugal
-Spanish
Dnipro:
-Russia
-Ukrain
how to remove repetitions ?
Some text for escape "
It looks like your post is mostly code; please add some more details." error
Your data structure is not appropriate for the solution.
Try below:
map<string, vector<string>> riverToCountryMap
And while inserting data:
riverToCountryMap[river].push_back(country);
You can use std::multimap for reverse order:
std::map<std::string, std::string> m {
{"Spanish", "Taho"},
{"France", "Rhine"},
{"Ukrain", "Dnipro"},
{"Germany", "Rhine"},
{"Russia", "Dnipro"},
{"Portugal", "Taho"},
};
std::multimap<std::string, std::string> rev;
for (const auto& p : m) {
rev.emplace(p.second, p.first);
}
Demo
You might prefer std::map<std::string, std::vector<std::string>> over std::multimap.
I have to read two text files and then compare words from second file with the first one. Then , I have to display KnownWords which are same words from both files and the remaining words which are not same are UnknownWords. Next Step is, I have to display most frequent known words in DisplayMostFreqKnownWords() and unknown words in DisplayMostFreqUnknownWords() functions. I have successfully completed DisplayMostFreqKnownWords() and so far Output is alright. I copied the same code from DisplayMostFreqKnownWords() to DisplayMostFreqUnknownWords() but in this is function it is not showing anything in the output. I dont know what is wrong. Can someone figure this one out.
Output is:
Displaying most frequent known words
Word Count
the 19
a 14
of 11
artificial 11
that 10
to 7
signal 7
and 7
in 6
they 5
Displaying most frequent unknown words
Word Count
Header file:
typedef map<string, vector<int> > WordMap;
typedef WordMap::iterator WordMapIter;
class WordStats
{
public:
WordStats();
void ReadDictionary();
void DisplayDictionary();
void ReadTxtFile();
void DisplayKnownWordStats();
void DisplayUnknownWordStats();
void DisplayMostFreqKnownWords();
void DisplayMostFreqUnknownWords();
private:
WordMap KnownWords;
WordMap UnknownWords;
WordMapIter Paragraph;
set<string> Dictionary;
char Filename[256];
}
My program:
// Displays 10 most frequent words in KnownWords
void WordStats::DisplayMostFreqKnownWords(){
int count;
multimap<int,string > displayFreqWords;// new map with int as key
(multimap because key could occur more than once)
multimap<int,string >::reverse_iterator rit = displayFreqWords.rbegin();
for (Paragraph = KnownWords.begin(); Paragraph != KnownWords.end();
++Paragraph){ // iterate map again
string word = (*Paragraph).first;
int cnt = (*Paragraph).second.size();
displayFreqWords.insert(pair<int,string>(cnt,word));
}
// multimap<int,string>::iterator rit; // iterator for new map
cout <<" Word Count\n";
for(; count<=10 && rit!=displayFreqWords.rend(); rit++, ++count){
string word = (*rit).second;
int cnt = (*rit).first;
cout << setw(15) << word << setw(10) << cnt << endl;
}
}
// Displays 10 most frequent words in UnknownWords
void WordStats::DisplayMostFreqUnknownWords(){
int count;
multimap<int,string > displayFreqUnknownWords;
multimap<int,string >::reverse_iterator rrit =
displayFreqUnknownWords.rbegin();
for (Paragraph = UnknownWords.begin(); Paragraph !=
UnknownWords.end(); ++Paragraph){
string word = (*Paragraph).first;
int cnt = (*Paragraph).second.size();
displayFreqUnknownWords.insert(pair<int,string>(cnt,word));
}
// multimap<int,string>::iterator rit; // iterator for new map
cout <<" Word Count\n";
for(; count<=10 && rrit!=displayFreqUnknownWords.rend(); rrit++, ++count){
string wrd = (*rrit).second;
int ccnt = (*rrit).first;
cout << setw(15) << wrd << setw(10) << ccnt << endl;
}
}
Here's a way to express what I think is your use case. I have used c++17 tuple expansion.
I have used unordered_map to deduce which words are known or unknown, and two multimaps to determine known and unknown word frequency.
Hope it's helpful.
#include <sstream>
#include <tuple>
#include <string>
#include <unordered_map>
#include <algorithm>
#include <iterator>
#include <map>
#include <iostream>
#include <iomanip>
#include <fstream>
// Set this to 1 to run a static test
#define TESTING 0
#if TESTING
using input_type = std::istringstream;
std::tuple<input_type, input_type> open_inputs() {
return {
std::istringstream("the big black cat sat on the grey mat"),
std::istringstream("the gold small cat lay on the purple mat")
};
}
#else
using input_type = std::ifstream;
std::tuple<input_type, input_type> open_inputs() {
return {
std::ifstream("left_file.txt"),
std::ifstream("right_file.txt"),
};
}
#endif
struct Counts {
int left_count = 0, right_count = 0;
int total() const {
return left_count + right_count;
}
bool is_known() const {
return left_count && right_count;
}
};
template<class F>
void for_each_word_in_file(std::istream &is, F f) {
std::for_each(std::istream_iterator<std::string>(is),
std::istream_iterator<std::string>(),
f);
}
int main() {
// open files
auto[left, right] = open_inputs();
auto known_words = std::unordered_map<std::string, Counts>();
// count words in each file
for_each_word_in_file(left, [&known_words](auto &&word) {
++known_words[word].left_count;
});
for_each_word_in_file(right, [&known_words](auto &&word) {
++known_words[word].right_count;
});
// map counts to words, in descending order, allowing multiple entries of the same count
std::multimap<int, std::string, std::greater<>> known_ordered, unknown_ordered;
// iterate all words seen, putting into appropriate map
for (auto&&[word, counts] : known_words) {
(counts.is_known() ? known_ordered : unknown_ordered)
.emplace(counts.total(), word);
}
// emit results
std::cout << "Known words by frequency\n";
for (auto&&[freq, word] : known_ordered) {
std::cout << std::setw(15) << word << " " << freq << '\n';
}
std::cout << "\nUmknown words by frequency\n";
for (auto&&[freq, word] : unknown_ordered) {
std::cout << std::setw(15) << word << " " << freq << '\n';
}
}
I have a string like "aabcdba" now I want to store the position of different character's position. I am trying to store using vector and unordered_map. Is there any good approach to store the position of different characters?
void topKFrequent(string s) {
vector<vector<int> >v(123);
//unordered_map<char, vector<int>>m;
for(int i=0;i<s.size();i++) {
v[s[i]].push_back(i);
// m[s[i]].push_back(i);
}
for(int i=0;i<123;i++) {
for(int j=0;j<v[i].size();j++) {
char ch=i;
cout<<ch<<"->"<<v[i][j]<<endl;
}
}
}
if string = "aabcdba", I want the following result:
a->0,1,6;
b->2,5;
c->3;
d->4;
You could use a map<char, vector<unsigned int> >.
#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;
map<char, vector<unsigned int> > storePos(string s)
{
map<char, vector<unsigned int> > charPos;
for(int i=0;i<s.size();i++)
{
auto itr = charPos.find(s[i]);
if(itr != charPos.end())
{
itr->second.push_back(i);
}
else
{
charPos[s[i]] = vector<unsigned int>(1, i);
}
}
return charPos;
}
int main(void)
{
string example = "aabcdba";
auto result = storePos(example);
for(auto itr1 = result.begin(); itr1 != result.end(); itr1 ++)
{
cout << "Letter: " << itr1->first << ", Locations: ";
for(auto itr2 = itr1->second.begin(); itr2 != itr1->second.end();
itr2 ++)
{
cout << *itr2 << " ";
}
cout << endl;
}
}
If you really want to store ordinal positions in the original string sequence, you can do so with either an unordered or ordered map of char to vector, where char is the key, and the vector contains the positions. Using an unordered map will not give you the lexicographical ordering of keys you seem to be seeking, but will nonetheless give you accurate positional vectors.
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
int main()
{
std::string s = "aabcdba";
std::unordered_map<char, std::vector<unsigned int>> mymap;
for (unsigned i=0; i<s.size(); ++i)
mymap[s[i]].push_back(i);
for (auto const& pr : mymap)
{
std::cout << pr.first << "->";
auto it = pr.second.cbegin();
std::cout << *it;
while (++it != pr.second.cend())
std::cout << ',' << *it;
std::cout << ";\n";
}
}
Output
d->4;
c->3;
b->2,5;
a->0,1,6;
If you want lexicographical ordering, the simplest alternative is to simply using a regular ordered map instead. Changing only this:
std::unordered_map<char, std::vector<unsigned int>> mymap;
to this:
std::map<char, std::vector<unsigned int>> mymap;
and including the appropriate header delivers us this for output:
a->0,1,6;
b->2,5;
c->3;
d->4;
which fits exactly what you seem to be looking for.
A possible implementation to store the positions could be using unordered_multimap: (where the key characters can be repeated).
void storePos(string s) {
unordered_multimap<char, int>m;
for(int i=0;i<s.size();i++) {
m.insert(make_pair(s[i],i));
}
}
[EDITED]
But the output may depend on how you use it, or print out the data.
For example, consider the use of a std::multimap instead of std::unordered_map, to populate it you just do:
multimap<char, int>m;
void storePos(string s) {
for(int i=0;i<s.size();i++) {
m.insert(make_pair(s[i],i));
}
}
And to print the data you could have the following method:
void printPos()
{
std::multimap<char,int>::iterator it,itup;
for (it = m.begin(); it != m.end(); )
{
cout << (*it).first << " -> ";
itup = m.upper_bound ((*it).first );
// print range [it,itup):
for (it; it!=itup; ++it)
{
cout << (*it).second << ", ";
}
cout << endl;
}
}
Output:
a -> 0, 1, 6,
b -> 2, 5,
c -> 3,
d -> 4,
Try this!
I have a unordered_map AvailableRooms of hotels against number of rooms. Like
Sheridan -> 10
Marriot ->12
I have a map hotelOnDate which stores, string date converted to unix time against hotel.
142356789 -> Sheridan
142356749 -> Marriot
Now when I try to access the hotels unordered_map values using the map keys, I get a 0.
for(auto it = hotelOnDate.begin(); it != hotelOnDate.end(); it++){
std::cout<<AvailableRooms[it->second]<<std::endl;
}
AvailableRooms["Sheridan"] though gives the correct output 10.
What am I doing wrong here?
I tried the same thing in my code and seems to work for me.
#include <iostream>
#include <string>
#include <unordered_map>
#include <map>
int main ()
{
std::map<std::string,std::string> mymap = {
{ "Mars", "g"},
{ "Saturn", "h"},
{ "Jupiter", "i" } };
std::unordered_map<std::string,std::string> imap = {{"g","1"},{"h","2"}};
for (auto it = mymap.begin(); it != mymap.end(); it++) {
std::cout << it->first << ": " <<imap[ it->second ] << std::endl;
}
}
return 0;
}
I'm working on map and I have following nested map and initialized with some values:
map<string, map<int, int> > wordsMap;
map<int, int> innerMap;
map<int, int>::iterator iti;
for(int i = 2; i < argc; i++)
{
wordsMap[argv[i]].insert(pair<int, int>(0,0));
}
And after some processing I'm trying to change the content if inner map, I use following code:
while(some_condition)
{
i = 0
for( it = wordsMap.begin() ; it != wordsMap.end(); it++)
{
innerMap = it->second;
int cnt = count(words.begin(), words.end(), it->first);
if(cnt != 0){
wordsMap[it->first][i] = cnt;
}
}
i++;
}
In the above scenario, How to change the value of first key (i.e. "0") and its value used while initialization of the inner map with another key-value pair?
You can't change the key of an element in an std::map. Doing so would break ordering.
Instead, you must insert a new element in the map with the key you want, and delete the previous element from the map.
I'm not sure if I understand your intend. I assume you want to save,
<KEY : file_name, VALUE : <KEY : line, VALUE : words count>>
And you don't want to save second map if there is no words.
So, I wrote below code.
If you want to not present second map, just keep empty map through not inserting key-value.
Additionally, sincestd::map is an associative container, which means it is saved sorted based on Key value, you should try to avoid change the key value after saving it.
#include "stdafx.h"
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
typedef std::map<int, int> WORDS_COUNT_MAP_T; //for line, words count
typedef std::map<string, WORDS_COUNT_MAP_T> FILE_WORDS_COUNT_MAP_T; //for file name, WORDS_COUNT_MAP_T
int _tmain(int argc, _TCHAR* argv[])
{
FILE_WORDS_COUNT_MAP_T file_words_count_map;
//Input dummy data for test
//init file names
std::vector<string> file_names;
file_names.push_back("first");
file_names.push_back("second");
file_names.push_back("third");
//get and set words count in each file
for_each(file_names.begin(), file_names.end(), [&](const string& file_name)
{
//Just for test
WORDS_COUNT_MAP_T words_count_map;
if(file_name == "second")
{
//not find words, so nothing to do
}
else
{
words_count_map[0] = 10;
words_count_map[1] = 20;
}
file_words_count_map.insert(FILE_WORDS_COUNT_MAP_T::value_type(file_name, words_count_map));
});
//print
for_each (file_words_count_map.begin(), file_words_count_map.end(), [&](FILE_WORDS_COUNT_MAP_T::value_type& file_words_map)
{
cout << "file name : " << file_words_map.first << endl;
WORDS_COUNT_MAP_T words_count_map = file_words_map.second;
for_each (words_count_map.begin(), words_count_map.end(), [](WORDS_COUNT_MAP_T::value_type& words_map)
{
cout << "line : " << words_map.first << ", count : " << words_map.second << endl;
});
cout << "----" << endl;
});
getchar();
return 0;
}
This code will print like below,