C++ Multimap Printing - c++

I'm trying to make a name, and then give a list of courses this person has taken. Here is my code currently:
#include <iostream>
#include <string>
#include <map>
#include <list>
using namespace std;
int main()
{
multimap<string,string> students;
students.insert(make_pair("john","cs1"));
students.insert(make_pair("john","cs2"));
for (auto itr = students.begin(); itr != students.end(); ++itr)
{
cout << itr->first << '\t' << itr->second << '\n';
}
}
This prints out:
John CS1
John CS2
If I wanted to make it print out the first value and then print out all second values, how would I do this? Do I need to use a list as the second value or something? Or is this doable with just multimaps? For example:
John CS1 CS2

You can use equal_range to achieve what you wanted, see:
std::string current_key = "";
for (auto itr = students.begin(); itr != students.end(); ++itr)
{
if(current_key == itr->first) {
continue;
} else {
current_key = itr->first;
}
const auto result = students.equal_range(itr->first);
cout << itr->first << ": ";
for(auto it = result.first; it != result.second; ++it) {
cout << it->second << " ";
}
cout << endl;
}
See working example here: https://ideone.com/RqCFOk

You'll may eventually end up creating a class to model a student, in the meantime, you could just iterate over the multimap container and check if the current key is the same as the previous:
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <string>
using students_t = std::multimap<std::string, std::string>;
void print_students_list(students_t const& students)
{
// Start printing the name of the first student and the first course (the first key-value
// pair) if the container is not empty.
auto student{ students.cbegin() };
if ( student == students.cend() )
return;
std::cout << std::setw(12) << std::left << student->first
<< std::setw(8) << student->second;
// Then iterate over the rest of the container printing the name (after a newline)
// only if it's different from the previous one.
for ( auto prev{ student++ }; student != students.cend(); prev = student, ++student )
{
if ( student->first != prev->first )
std::cout << '\n' << std::setw(12) << student->first;
std::cout << std::setw(8) << student->second;
}
std::cout << '\n';
}
int main()
{
students_t students {
{"john", "cs1"},
{"john", "cs2"},
{"Karen", "cs2"},
{"Karen", "nc1"},
{"Karen", "nc2"},
{"Bob", "nc1"}
};
print_students_list(students);
}

Related

Could not print map of map value in C++

I have tried below code snippets to print map of map values but I could not able to access second map values.
#include <iostream>
#include <iterator>
#include <map>
#include <string>
using namespace std;
int main()
{
map< string, std::map<std::string, int> > someStorage;
//First key values
someStorage["key1"]["This Is Layer one"] = 100;
someStorage["Key1"]["This Is Layer Two"] = 120;
//second key, values
someStorage["key2"]["This Is Layer one"] = 110;
someStorage["key2"]["This Is Layer Two"] = 110;
map< string, std::map<std::string, int> > ::iterator itr;
cout << "\nThe map is : \n";
for (itr = someStorage.begin(); itr != someStorage.end(); ++itr)
{
cout << '\t' << itr->first;
//<< '\t' << (itr->second).first << '\n' <==problematic part
//<< '\t' << (itr->second).second << '\n'; <==problematic part
}
cout << endl;
return 0;
}
How to print/access these values and how do I differentiate "This Is Layer
one" for "key1" and "key2". Because I can see that it is getting
overwritten if we assign key2 value, key1 has same. Why?
Also I am expecting below key value pairs
Key1 => {This Is Layer one, 100}
{This Is Layer Two, 120}
Key2 =>{This Is Layer one, 110}
{This Is Layer Two, 110}
.
In addition to the other answers here, you can use structured binding (since c++17) to simplify this:
for (auto const& [key, val] : someStorage) { // val = second map
for (auto const& [k, v] : val) { // k = first, v = second
cout << key << ' ' << k << ' ' << v << '\n';
}
}
You need a second, inner loop to traverse the nested std::map. Like this:
for (auto itr = someStorage.cbegin(); itr != someStorage.cend(); ++itr)
{
cout << itr->first << " => ";
for (auto innerItr = itr->second.cbegin(); innerItr != itr->second.cend(); ++innerItr)
{
cout << innerItr->first << " : " << innerItr->second << " ";
}
cout << "\n";
}
Note that for the desired output, you need to capitalize the keys such that they are "Key1" and "Key2" (this is currently a typo in your question). Note further that I changed to begin/end member functions to cbegin/cend, as the loop doesn't modify the container.
You'll need to iterate over your inner map as well, something like:
for (auto itr1 = someStorage.begin(); itr1 != someStorage.end(); ++itr1)
{
cout << '\t' << itr->first << ":\n";
for (auto itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2)
{
cout << "\t\t" << itr2->first << '\n';
cout << "\t\t" << itr2->second << '\n';
}
}
Thank you for the output. My Gcc version did not support auto iterate
for (itr1 = someStorage.begin(); itr1 != someStorage.end(); ++itr1)
{
cout << '\t' << itr1->first << ":\n";
std::map<std::string, int> ::iterator itr2;
for (itr2 = itr1->second.begin(); itr2 != itr1->second.end(); ++itr2)
{
cout << "\t\t" << itr2->first << '\n';
cout << "\t\t" << itr2->second << '\n';
}
}

How to iterate through a List function?

I'm running a test program where I make a list of strings and try to find which strings have a certain suffix or prefix.
#include <iostream>
#include <list>
#include <string>
using namespace std;
list<string> beginWith(const string& pre, list <string> test);
list<string> endWith(const string& suf,list <string> test);
int main(){
list <string> testList(5);
string suffix = "able";
string prefix = "M";
testList.push_back("Agreeable");
testList.push_back("Doable");
testList.push_back("Machine");
testList.push_back("Makeable");
testList.push_back("Available");
for(list <string>::const_iterator it = testList.begin(); it != testList.end(); it++){
cout << *it << endl;
}
for(list <string>::const_iterator it = beginWith(prefix, testList).begin(); it != beginWith(prefix, testList).end(); it++){
cout << *it << endl;
}
for(list <string>::const_iterator it = endWith(suffix, testList).begin(); it != endWith(suffix, testList).end(); it++){
cout << *it << endl;
}
return 0;
}
list<string> beginWith(const string& pre, list<string> test){
list <string> answer;
for(list <string>::const_iterator it = test.begin(); it != test.end(); it++){
if(pre == it->substr(0, pre.length())){
answer.push_back(*it);
}
}
return answer;
}
list<string> endWith(const string& suf, list <string> test){
list <string> answer;
for(list <string>::const_iterator it = test.begin(); it != test.end(); it++){
if(suf == it->substr(it->length() - suf.length() , it->back())){
answer.push_back(*it);
}
}
return answer;
}
I declared a list of strings printed them out with the first for-loop. I also have 2 functions which will iterate through that list and then return a list of strings that have a certain prefix or suffix. I'll print those out with the 2nd and 3rd for-loop. The 1st for-loop prints out correctly however, I get a segmentation fault: 11 when I print out the 2nd and 3rd for loops. I'm confused as to how I would get those for-loops to iterate through the list functions and print out the contents.
beginWith and endWith return a list by value. This makes the for-loops call begin() and end() on different copies of the list.
list<string> beginWith(const string& pre, list<string> test) {
list <string> answer;
for (auto word : test) // Use C++ auto to iterate collection
{
cout << "Testing " << word << " against " << pre << " ... ";
if (word.find(pre) == 0) // From http://thispointer.com/c-check-if-a-string-starts-with-an-another-given-string/
{
cout << "match!";
answer.push_back(word);
}
cout << '\n';
}
return answer;
}
list<string> endWith(const string& suf, list <string> test) {
list <string> answer;
for (auto word : test)
{
cout << "Testing " << word << " against " << suf << " ... ";
if (word.size() >= suf.size() &&
word.compare(word.size() - suf.size(), suf.size(), suf) == 0) // From http://thispointer.com/c-how-to-check-if-a-string-ends-with-an-another-given-string/
{
cout << "match!";
answer.push_back(word);
}
cout << '\n';
}
return answer;
}
int main(int argc, wchar_t *argv[])
{
list <string> testList {}; // Create empty list, not list with five elements
string suffix = "able";
string prefix = "M";
testList.push_back("Agreeable");
testList.push_back("Doable");
testList.push_back("Machine");
testList.push_back("Makeable");
testList.push_back("Available");
for (auto word : testList) {
cout << word << '\n';
}
auto prefixedWords = beginWith(prefix, testList);
cout << "Prefixed words: \n";
for (auto prefixed : prefixedWords) {
cout << " " << prefixed << '\n';
}
auto suffixedWords = endWith(suffix, testList);
cout << "Suffixed words: \n";
for (auto suffixed : suffixedWords) {
cout << " " << suffixed << '\n';
}
return 0;
}
Program output:
Agreeable
Doable
Machine
Makeable
Available
Testing Agreeable against M ...
Testing Doable against M ...
Testing Machine against M ... match!
Testing Makeable against M ... match!
Testing Available against M ...
Prefixed words:
Machine
Makeable
Testing Agreeable against able ... match!
Testing Doable against able ... match!
Testing Machine against able ...
Testing Makeable against able ... match!
Testing Available against able ... match!
Suffixed words:
Agreeable
Doable
Makeable
Available

Counter for items in an inventory using iterators

I'm somewhat new to vectors and iterators and I'm trying to figure out how to display an amount of items using an iterator. One example would be you have 5 apples. I would want it to output "5x Apple" or something of that sort. I have no idea how one might accomplish this. Here's a simple code that has the user put in a string to add to the inventory.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string item;
vector<string> inventory;
vector<string>::iterator iter;
int main()
{
while(true){
cin >> item;
inventory.push_back(item);
cout << "INVENTORY:\n";
for(iter = inventory.begin(); iter != inventory.end(); iter++)
cout << *iter << endl;
}
}
EDIT: I'm trying to make an inventory system for a game. That's why I thought i may need an iterator. If there's a better way to make an inventory system than using an iterator, please let me know. Apologies, i should have clarified.
An iterator lets you iterate through a container, but it does not do any counting for you.
A container's size() tells you how many items are in the container, but if you have different types of items then you have to count them yourself.
For instance, say you have 4 "apple" and 1 "orange".
You have to look at each item entered and count it as needed, eg:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> inventory;
int numApples = 0;
int numOranges = 0;
int numOther = 0;
int main()
{
string item;
while (cin >> item)
{
inventory.push_back(item);
if (item == "apples")
++numApples;
else if (item == "orange")
++numOranges;
else
++numOther;
}
cout << "INVENTORY:\n";
for (vector<string>::iterator iter = inventory.begin(); iter != inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : inventory)
cout << s << endl;
*/
cout << "# apples: " << numApples << endl;
cout << "# oranges: " << numOranges << endl;
cout << "# other: " << numOther << endl;
return 0;
}
Or, you might consider using std::count_if(), eg:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> inventory;
bool isApple(const string &s) { return (s == "apple"); }
bool isOrange(const string &s) { return (s == "orange"); }
bool isOther(const string &s) { return !(isApple(s) || isOrange(s)); }
int main()
{
string item;
while (cin >> item)
inventory.push_back(item);
cout << "INVENTORY:\n";
for (vector<string>::iterator iter = inventory.begin(); iter != inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : inventory)
cout << s << endl;
*/
cout << "# apples: " << count_if(inventory.begin(), inventory.end(), isApple) << endl;
cout << "# oranges: " << count_if(inventory.begin(), inventory.end(), isOrange) << endl;
cout << "# other: " << count_if(inventory.begin(), inventory.end(), isOther) << endl;
/* or, if you are using C++11 or later:
cout << "# apples: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s == "apple"); }) << endl;
cout << "# oranges: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s == "orange"); }) << endl;
cout << "# other: " << count_if(inventory.begin(), inventory.end(), [](auto &s){ return (s != "apple") && (s != "orange"); }) << endl;
*/
return 0;
}
Update: based on another question you posted, try something more like this instead:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
vector<string> other_inventory;
int numApples = 0;
int numOranges = 0;
int main()
{
string item;
while (cin >> item)
{
if (item == "apples")
++numApples;
else if (item == "orange")
++numOranges;
else
other_inventory.push_back(item);
}
cout << "INVENTORY:\n";
if (numApples > 0)
cout << "# apples: " << numApples << endl;
if (numOranges > 0)
cout << "# oranges: " << numOranges << endl;
for (vector<string>::iterator iter = other_inventory.begin(); iter != other_inventory.end(); ++iter)
cout << *iter << endl;
/* or, if you are using C++11 or later:
for (string &s : other_inventory)
cout << s << endl;
*/
return 0;
}
A way to simplify this is to sort the items in the inventory. That will bring the identical ones together, which simplifies counting them. Start at the beginning, count the number of consecutive items that match the current one, display it, and continue with the first non-matching one.
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::string item;
std::vector<std::string> inventory;
while (true) {
std::cin >> item;
if (item == "quit") return 0;
inventory.push_back(item);
std::sort(inventory.begin(), inventory.end());
std::cout << "INVENTORY:\n";
auto current = inventory.begin();
while (current != inventory.end()) {
int count = 1;
auto probe = current + 1;
while (probe != inventory.end() && *probe == *current) {
++count;
++probe;
}
std::cout << count << "x " << *current << '\n';
current = probe;
}
std::cout.flush();
}
return 0;
}
In more detail, if your inventory is {"orange", "apple", "orange"}, then the sort will rearrange the order to {"apple", "orange", "orange"}. Note that the identical ones are together.
Now the iterator current starts at the beginning ("apple"). We set count to 1 because we know there's at least 1. We set the iterator probe to point to the next item ("orange"). Since the value at probe doesn't match the value at current, the inner loop does nothing. We print count and the current item ("apple"). We continue by setting current to probe, because, at this point, probe will point to the first item that didn't match the current one.
On the second iteration, current refers to the first "orange". We reset count to 1 and start probe at the next item ("orange"). Since the values at match, we increment count (now 2) and advance probe (now at the end of the inventory). We print count (2) and the current item ("orange"), and set current to probe (end of the list). The outer loop condition sees we're at the end of the inventory, so the loop terminates.
inventory.size()
returns the number of items in your vector.
I don't see how you would need an iterator for that task.

Detecting even and odd C++ vector iterators

I searched and I'm surprised this hasn't been asked yet. I know how to do it with a simple loop, how about with vector iterators?
for( std::vector<int>::iterator it = somevector.begin(); it != somevector.end(); ++it )
{
//Conditions stating a certain vector has an even or odd index.
}
Sorry for not clarifying, I meant detecting whether the index of a vector is odd or even.
This would be one simple way:
{
bool is_even = true;
for (const auto& v: somevector) {
if (is_even) even_handler(v);
else odd_handler(v);
is_even = !is_even;
}
}
Want a more complicated solution? No problem:
#include <iostream>
#include <string>
#include <utility>
#include <vector>
using std::next;
template<typename Iter, typename Func, typename...Funcs>
void RotateHandlers(Iter b, Iter e, Func f, Funcs...fs) {
if (b != e) {
f(*b);
RotateHandlers(next(b), e, fs..., f);
}
}
int main() {
std::vector<std::string> v({"Hello", "world", "it's", "really", "great", "to", "be", "here"});
RotateHandlers(v.begin(), v.end(),
[](const std::string& s){std::cout << "First|" << s << std::endl;},
[](const std::string& s){std::cout << "Then |" << s << std::endl;},
[](const std::string& s){std::cout << "And |" << s << std::endl
<< " |" << std::string(s.size(), '-') << std::endl;}
);
return 0;
}
See it here: http://ideone.com/jmlV5F
I'm going to guess you meant you wanted to detect if the current index is even or odd:
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> somevector;
somevector.push_back(1);
somevector.push_back(2);
somevector.push_back(4);
somevector.push_back(8);
somevector.push_back(111605);
for (auto it = somevector.begin(); it != somevector.end(); ++it)
{
// current index
const auto index = std::distance(somevector.begin(), it);
if ((index % 2) == 0) // even
{
std::cout << "Index " << index << " (even) is: " << *it;
}
else
{
std::cout << "Index " << index << " (odd) is: " << *it;
}
std::cout << std::endl;
}
}
You can get the distance between iterators with std::distance. (Index being distance from the start.)
If I understand the question [before its last edit] correctly, an option is:
bool is_odd(const std::vector<int> &somevector) {
for( std::vector<int>::iterator it = somevector.begin(); it != somevector.end(); ++it ) {
//Conditions stating a certain vector is even or odd.
if (*it % 2 == 0) {
return false;
}
}
return true;
}
respectively for "even vectors".

How can I display the content of a map on the console?

I have a map declared as follows:
map < string , list < string > > mapex ; list< string > li;
How can I display the items stored in the above map on the console?
Update (Back to the future): with C++11 range-based for loops –
std::map<Key, Value> m { ... /* initialize it */ ... };
for (const auto &p : m) {
std::cout << "m[" << p.first << "] = " << p.second << '\n';
}
Well it depends on how you want to display them, but you can always iterate them easily:
typedef map<string, list<string>>::const_iterator MapIterator;
for (MapIterator iter = mapex.begin(); iter != mapex.end(); iter++)
{
cout << "Key: " << iter->first << endl << "Values:" << endl;
typedef list<string>::const_iterator ListIterator;
for (ListIterator list_iter = iter->second.begin(); list_iter != iter->second.end(); list_iter++)
cout << " " << *list_iter << endl;
}
I'd try the following
void dump_list(const std::list<string>& l) {
for ( std::list<string>::const_iterator it = l.begin(); l != l.end(); l++ ) {
cout << *l << endl;
}
}
void dump_map(const std::map<string, std::list<string>>& map) {
for ( std::map<string,std::list<string>>::const_iterator it = map.begin(); it != map.end(); it++) {
cout << "Key: " << it->first << endl;
cout << "Values" << endl;
dump_list(it->second);
}
I'm a little off topic here...
I guess you want to dump the map content for debugging. I like to mention that the next gdb release (version 7.0) will have a built in python interpreter which will be used by the gcc libstdc++ to provide stl pretty printers. Here is an example for your case
#include <map>
#include <map>
#include <list>
#include <string>
using namespace std;
int main()
{
typedef map<string, list<string> > map_type;
map_type mymap;
list<string> mylist;
mylist.push_back("item 1");
mylist.push_back("item 2");
mymap["foo"] = mylist;
mymap["bar"] = mylist;
return 0; // stopped here
}
which results in
(gdb) print mymap
$1 = std::map with 2 elements = {
["bar"] = std::list = {
[0] = "item 1",
[1] = "item 2"
},
["foo"] = std::list = {
[0] = "item 1",
[1] = "item 2"
}
}
Yay!
Another form, using <algorithm>:
void printPair(const pair<string, list<string> > &p)
{
cout << "Key: " << p.first << endl;
copy(p.second.begin(), p.second.end(), ostream_iterator<string>(cout, "\n"));
}
for_each(mapex.begin(), mapex.end(), printPair);
Test program:
#include <iostream>
#include <map>
#include <list>
#include <iterator>
#include <algorithm>
using namespace std;
void printPair(const pair<string, list<string> > &p)
{
cout << "Key: " << p.first << endl;
copy(p.second.begin(), p.second.end(), ostream_iterator<string>(cout, "\n"));
}
int main()
{
map<string, list<string> > mapex;
list<string> mylist1;
mylist1.push_back("item 1");
mylist1.push_back("item 2");
mapex["foo"] = mylist1;
list<string> mylist2;
mylist2.push_back("item 3");
mylist2.push_back("item 4");
mylist2.push_back("item 5");
mapex["bar"] = mylist2;
for_each(mapex.begin(), mapex.end(), printPair);
}
You can write a quite generic overloaded function, which is good for two purposes:
It works with any map.
It allows for using <<.
The function is
template<class key_t, class value_t>
ostream& operator<<(ostream& os, const map<key_t, value_t>& m) {
for (typename map<key_t, value_t>::const_iterator it = m.begin();
it != m.end(); it++) {
os << "Key: " << it->first << ", Value: " << it->second;
}
return os;
}
cout << will work with any map for which << is defined for typenames key_t and value_t. In your case, this is not defined for value_t (= list<string>), so you also have to define it.
In a similar spirit, you can use
template<class T>
ostream& operator<<(ostream& os, const list<T>& l) {
for (typename list<T>::const_iterator it = l.begin(); it != l.end(); it++) {
os << "\"" << *it << "\", ";
}
return os;
}
So, you may:
Add these two functions.
Add the prototypes where needed.
Use using namespace std; (or add std:: as needed).
Use, e.g.,
cout << mapex << endl;
cout << li << endl;
Remember that if there is any other viable candidate for the <<s just defined (which I take there is not, otherwise you would likely not ask this question), it may take precedence over the present ones.
If you can use C++11 features, then I think range-based for loops as proposed in The Paramagnetic Croissant's answer provide the most readable option. However, if C++17 is available to you, then you can combine those loops with structured bindings to further increase readability, because you no longer need to use the first and second members. For your specific use case, my solution would look as follows:
std::map<std::string, std::list<std::string>> mapex;
mapex["a"] = { "1", "2", "3", "4" };
mapex["b"] = { "5", "6", "7" };
for (const auto &[k, v] : mapex) {
std::cout << "m[" << k.c_str() << "] =";
for (const auto &s : v)
std::cout << " " << s.c_str();
std::cout << std::endl;
}
Output:
m[a] = 1 2 3 4
m[b] = 5 6 7
Code on Coliru