sap
sap

Reputation: 679

map contains value as a list+how to print in C++

I have a map having strings as keys and lists of file names as values. ex: Map(firstDir, list(file1,file2,file3))

I know that by using following code I can print value which is of String

{
    cout << "Key: " << pos->first << endl;
    cout << "Value:" << pos->second << endl;
}

But if pos->second contains a List, how to display?

Upvotes: 4

Views: 2393

Answers (7)

Volodymyr Bochko
Volodymyr Bochko

Reputation: 11

Since you are using STL the most simple way to print such structure is the next one:

#include <iostream> 
#include <map>
#include <list>
#include <string>

using namespace std;

int main()
{
    map<string, list<string>> sample;

   ... //fill the map

    for (auto itr : sample){
        cout << itr.first << ":\t" << endl;
        for (auto innerItr : sample.second)
            cout << innerItr << " ";
        cout << endl;
    }
}

Upvotes: 1

Valentin H
Valentin H

Reputation: 7448

Strait forward version (-:

#include <map>
#include <list>
#include <string>
#include <iostream>
#include <sstream> // only for generating testdata

typedef std::list<std::string> TStringList;
typedef std::map<std::string, TStringList> TStringListMap;

TStringListMap myMap;

int main()
{
  // Generating testdata
  for (int i=0;i<10;i++)
  {
    std::stringstream kstr;
    kstr << i;
    std::string key = kstr.str();        
    for (int ii=0;ii<=i;ii++)
    {
      std::stringstream vstr;
      vstr << ii;
      myMap[key].push_back( vstr.str() );
    }  
  }

  //Print map
  for ( TStringListMap::const_iterator it = myMap.begin(), end = myMap.end(); it != end; ++it )
  {
    std::cout << it->first<< ": ";
    for( TStringList::const_iterator lit = it->second.begin(), lend = it->second.end(); lit != lend; ++lit )
    {
      std::cout << *lit << " ";
    }
    std::cout << std::endl;
  }
  return 0;
}

Output:

0: 0
1: 0 1
2: 0 1 2
3: 0 1 2 3
4: 0 1 2 3 4
5: 0 1 2 3 4 5
6: 0 1 2 3 4 5 6
7: 0 1 2 3 4 5 6 7
8: 0 1 2 3 4 5 6 7 8
9: 0 1 2 3 4 5 6 7 8 9

Upvotes: 0

CashCow
CashCow

Reputation: 31445

What you want to be able to do though is to create a template that can output any printable sequence, i.e. a sequence of printable items. You also want to be able to customise how you start, end and delimit the sequence.

So create your own wrapper class. Now because it is your wrapper you can overload operator<< happily on it without interfering with an external namespace.

You could use a boost::range in its constructor, or a templated being/end sequence or a templated collection.

Also take as parameters your delimiters. You can have reasonable defaults if you want though,

Finally when you wish to print one, you just do something like:

std::cout << MySequenceFormatter( seq.begin(), seq.end(), delim, startofSeq, endOfSeq ) << std::endl;

When outputting maps, you can use a boost::transform_iterator in between to transform each std::pair as you iterate through the sequence. Then you can have you own pair formatter too. In fact you can do this for any sequence where you wish to use a custom method to print the items themselves.

Upvotes: 0

Roger Pate
Roger Pate

Reputation:

Use a library which overloads stream inserters for containers, such as my example:

void example(MapType const &m) {
  using namespace kniht::container_inserters;  // must be enabled in this scope
  MapType::const_iterator x = m.begin();

  cout << *x << '\n';  // can print the pair directly

  cout << "Key: " << x->first << '\n';  // or format it yourself
  cout << "Value: " << x->second << '\n';
  // output for a list: [a, b, c]
}

You can extract the used functions from my header or simply copy it elsewere (it's self-contained, but does have other utilities).

Upvotes: 2

Bj&#246;rn Pollex
Bj&#246;rn Pollex

Reputation: 76856

The first thing you would have to decide is how do you want the list to be displayed? Separated by commas or each entry in a new line perhaps? Then, you could overload the stream output operator for lists of strings:

std::ostream & operator<<(std::ostream & stream, const std::list<std::string> & object) {
    std::copy(object.begin(), object.end(), std::ostream_iterator<std::string>(std::cout, ", ")
}

This operator will get called everytime you write am std::list<std::string> to any output stream, and it will print the values of the list separated by commas.

Upvotes: 2

Armen Tsirunyan
Armen Tsirunyan

Reputation: 133072

overload operator << for list

std::ostream& operator << (std::ostream& out, std::list<ListElemType> const& lst)
{
   for(std::list<ListElemType>::iterator it = lst.begin(); it != lst.end(); ++it)
   {
       if(it != lst.begin())
          out << /*your delimiter*/;  
       out << *it;
   }
   return out;
}

now you can do what you want

cout << "Key: " << pos->first << endl << "Value:" << pos->second << endl; 

Upvotes: 7

Beno&#238;t
Beno&#238;t

Reputation: 16994

How about using Boost.Foreach ?

#include <boost/foreach.hpp>

{
    cout << "Key: " << pos->first << endl;
    cout << "Values:" << endl;
    BOOST_FOREACH(std::string const& file, pos->second)
    {
      cout << "\t" << file << endl;
    } 
}

Upvotes: 2

Related Questions