STL

Hello everyone !
Today I got a problem with templates. I'm not that good with them and I can't find usefull exercises.
Hope you can help me solving and understanding this question.

I have to write a loop to access the integers. Then fill it with few sample data.
list<map<set<string>,int> l;

Thanks


list<map<set<string>, int>> l;

I can't think of a reason anyone would ever need to store data that way, so I'm assuming the assignment is just supposed to make it incredibly difficult to use? Every time you want to access an integer you have to have an exact copy of the set of strings for the map key...
How about

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <list>
#include <map>
#include <set>
#include <string>
#include <iostream>

int main()
{
    std::list<std::map<std::set<std::string>, int>> l =
    {
      {
        {{"a"}, 0},
        {{"b"}, 1},
        {{"c"}, 2},
      },{
        {{"a", "b"}, 3},
        {{"a", "c"}, 4},
        {{"b", "c"}, 5}
      },{
        {{"a", "b", "c"}, 6},
      }
    };

    for(auto& m : l)
        for(auto& p: m)
            std::cout << p.second << ' ';
    std::cout << '\n';
}

live demo online: http://ideone.com/X19NOx
Last edited on
Thank you, it's a start for me.

What if I write a for loop that way to access integers ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <cstdlib>
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <string>

int main()
{
    std::list<std::map<std::set<std::string>, int>> l =
    {
      {
        {{"a"}, 0},
        {{"b"}, 1},
        {{"c"}, 2},
      },{
        {{"a", "b"}, 3},
        {{"a", "c"}, 4},
        {{"b", "c"}, 5}
      },{
        {{"a", "b", "c"}, 6},
      }
    };

it=s.find(int)
for(it=s.begin();it!=s.end();++it)
std::cout<< ' ' << *it;
std::cout<< '\n';

}
What if I write a for loop that way

it wouldn't compile

What is your desired output?
hmm.. I can omit output. For me it's just important to access the integers and fill some sample data.

here are you filling data ,right ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 std::list<std::map<std::set<std::string>, int>> l =
    {
      {
        {{"a"}, 0},
        {{"b"}, 1},
        {{"c"}, 2},
      },{
        {{"a", "b"}, 3},
        {{"a", "c"}, 4},
        {{"b", "c"}, 5}
      },{
        {{"a", "b", "c"}, 6},
      }
    };


Does this loop work to access integers ? I don't understand what's inside of it. I thought it could be : for(i=c.begin();i!=c.end();i++){cout << i*;}

1
2
3
4
 for(auto& m : l)
        for(auto& p: m)
            std::cout << p.second << ' ';
    std::cout << '\n';


thanks for your time
The link I gave is to an online compiler, where you can run the program with your modifications and see what the compiler has to say.

Rewriting the loop in the form that uses .begin() and .end(), it becomes

1
2
3
    for(auto list_it = l.begin(); list_it != l.end(); ++list_it)
        for(auto map_it = list_it->begin(); map_it != list_it->end(); ++map_it)
            std::cout << map_it->second << ' ';


live demo: http://ideone.com/fMSRRt
should I define that iterator before making the loop for ?
if yes, would it be correct writing :

list<int>::iterator list_it

??
No.

Type of "l" is std::list<std::map<std::set<std::string>, int> >, not std::list<int>.
Furthermore, const_iterator(s) are more appropriate as you will not modify the container(s) during "printout".
So to define iterator that case I should write :

std::list<std::map<std::set<std::string>, int> >::iterator list_it

right ?
For the outer loop, yes. Can you now guess the type of map_it in the inner loop?
A qiuick hint: if you're having to repeatedly write out types as complicated as std::list<std::map<std::set<std::string>, int> >, you might find it helpful to create some typedefs. It'll save on typing, and make your code easier to read. E.g.:

1
2
3
4
5
6
7
8
9
10
11
typedef std::set<std::string> StringSet;
typedef std::map<StringSet, int> MyMap;
typedef std::list<MyMap> MyList;

MyList l;

// ...

MyList::iterator list_it;

// ... 


EDIT: Of course, it helps if you can give these types more helpful names, relating to their purpose. For example, if your strings were names, you could have:

typedef std::set<std::string> NameSet;

But that's down to you, since you know what these data types are supposed to represent, and we don't. But the more self-explanatory you can make your types, the easier you'll find them to work with.
Last edited on
I guess I should write:

map<std::set<std::string>, int>::iterator map_it

Right?

Thanks everybody for good hints you are giving to me.
I wanna ask also, instead of entering data in this way:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 std::list<std::map<std::set<std::string>, int>> l =
    {
      {
        {{"a"}, 0},
        {{"b"}, 1},
        {{"c"}, 2},
      },{
        {{"a", "b"}, 3},
        {{"a", "c"}, 4},
        {{"b", "c"}, 5}
      },{
        {{"a", "b", "c"}, 6},
      }
    };


could also enter data writing that other way ?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

int main(){

typedef std::set<std::string> MySet;
typedef std::map<MySet, int> MyMap;
typedef std::list<MyMap> MyList;

My list l;

MySet.insert('a');
MySet.insert('b');
MySet.insert('c');

MyMap.insert(1);
MyMap.insert(2);
MyMap.insert(3);

std::list<std::map<std::set<std::string>, int> >::iterator list_it;
std::map<std::set<std::string>, int>::iterator map_it;

for(list_it = l.begin(); list_it != l.end(); ++list_it)
        for(map_it = list_it.begin(); map_it != list_it.end(); ++map_it)
            std::cout << map_it.second() << ' ';

}
MySet.insert('a');

That won't compile because MySet is a set of strings , not a set of characters.

Here's how you could fill the same list I made using single-element inserts:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <map>
#include <set>
#include <list>
#include <string>
#include <cassert>

int main()
{
   std::list<std::map<std::set<std::string>, int>> l1 =
    {
      {
        {{"a"}, 0},
        {{"b"}, 1},
        {{"c"}, 2},
      },{
        {{"a", "b"}, 3},
        {{"a", "c"}, 4},
        {{"b", "c"}, 5}
      },{
        {{"a", "b", "c"}, 6},
      }
    };

    typedef std::set<std::string> MySet;
    typedef std::map<MySet, int> MyMap;
    typedef std::list<MyMap> MyList;

    MySet s; s.insert("a");
    MyMap m; m[s] = 0;
    s.clear(); s.insert("b"); m[s] = 1;
    s.clear(); s.insert("c"); m[s] = 2;
    MyList l2; l2.push_back(m);

    s.clear(); s.insert("a"); s.insert("b");
    m.clear(); m[s] = 3;
    s.clear(); s.insert("a"); s.insert("c"); m[s] = 4;
    s.clear(); s.insert("b"); s.insert("c"); m[s] = 5;
    l2.push_back(m);
    s.clear(); s.insert("a"); s.insert("b"); s.insert("c");
    m.clear(); m[s] = 6;
    l2.push_back(m);

    assert(l1 == l2);
}
could also enter data writing that other way ?

That won't work. MySet and MyMap are types, not objects.

Cubbi's code shows how you use those types to create objects, and then pass them to other objects that contain them.
Topic archived. No new replies allowed.