help: list<struct> of list<string>

Trying to create a list that contains multiple keys with multiple content for each key. Do not want to use multimap because it would double the size of the files and memory use (content without key is already 1 mg and growing). Trying to use this method that would increase size only by about 10%. If I could solve the first error, which i believe is usage of the iterator index, I think the rest would be okay.

The output file to be read/written is:
key0
content1
...
contentN
...
keyN
content1
...
content2

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
45
46
47
48
49
50
51
52
struct myStruct
{
    string key;
    list<string> content;
};

list<myStruct> MyList;

list<myStruct>::iterator i; // Also tried as list<string>
list<string>::iterator j, k, l;

string tkey, tcontent;     // key and content to check for

// Test data
tkey = "a7b4";
tcontent = "this is a test";

// See if key exists
for (i = MyList.begin(); i != MyList.end(); i++)
{
    j = find(MyList[i].key.begin(), MyList[i].key.end(), tkey); // ERROR 1
    // If not, add key and content
    if (j == -1)                                                // ERROR 2
    {
        
        MyList[i].key.push_back(tkey);                          // ERROR 3
        MyList[i].content[0].push_back(tcontent);               // ERROR 3
    }
    // If yes, check if content exists
    else
    {
        for (k = MyList[i].content.begin(); k != MyList[i].content.end(); k++)
                // ERROR 3
        {
            l = find(MyList[i].content.begin(), MyList[i].content.end(), 
                     tcontent);                                 // ERROR 3
            // If no, add content to key
            if (1 == -1)                                        // ERROR 2
            {
                MyList[i].content[k].push_back(tcontent);       // ERROR 3
            }
        }
    }
}

// Display to check accuracy of storage
for (i = MyList.begin(); i != MyList.end(); i++)
{
    cout << MyList[i].key << endl;                              // ERROR 3
    for (j = MyList[i].key.begin(); j != MyList[i].key.end; j++)  // ERROR 3
       cout << "   " << MyList[j].content << endl;              // ERROR 3
}


ERRORS:
1) error: no match for call to '(std::__cxx11::list<myStruct>) (std::__cxx11::list<myStruct>::iterator&)'

2) error: no match for 'operator==' (operand types are 'std::__cxx11::list<std::__cx11::basic_string<char> >::iterator {aka std::_List_iterator<std::__cxx11::basic_string<char> >}' and 'int')

3) error: no match for 'operator[]' (operand types are 'std::__cxx11::list<myStruct>' and 'std::__cx11::list<myStruct>::iterator {aka std::_List_iterator<myStruct>}')
Last edited on
There's no random iterator access on std::list.

There's Boost, if you need an off the shelf one.
https://www.boost.org/doc/libs/1_67_0/libs/multi_index/doc/index.html

You totally misunderstand iterators. The are not indices. They are more like pointers.

And you even made the old "never use l as a variable name" error by accidentally typing it as the number 1 in if (1 == -1)

Try this (totally untested so you may need to fix up a couple things) :
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
45
46
struct myStruct
{
    string key;
    list<string> content;
};

list<myStruct> MyList;

list<myStruct>::iterator i; // Also tried as list<string>
list<string>::iterator j, k, l;

string tkey, tcontent; // key and content to check for

// Test data
tkey = "a7b4";
tcontent = "this is a test";

// See if key exists
for (i = MyList.begin(); i != MyList.end(); i++)
{
    j = find(i->key.begin(), i->key.end(), tkey);
    // If not, add key and content
    if (j == i->key.end())
    {
        i->key = tkey;
        i->content.push_back(tcontent);
    }
    // If yes, check if content exists
    else
    {
        l = find(i->content.begin(), i->content.end(), tcontent);
        // If no, add content to key
        if (l == i->content.end())
        {
            i->content.push_back(tcontent);
        }
    }
}

// Display to check accuracy of storage
for (i = MyList.begin(); i != MyList.end(); i++)
{
    cout << i->key << endl;
    for (j = i->content.begin(); j != i->content.end(); j++)
        cout << " " << *j << endl;
}

Hi tpb,

FYI, I have been away from programming for over 20 years and just now getting back into it helping others. Things have changed since Turbo C++ and Borland C++.

This is my first time using one of these sites as you can tell, since I was not able to get the code to appear in the box as yours did (I clicked the <> button that said code but did not seem to do anything).

I know using l can cause problems, but in the file it is an l. I must have keyed the 1 while I was transcribing it to this site. (I need to see if I can change the font in CodeBlocks so it will be more obvious if I happen to do this again).

Yesterday afternoon I had thought about the iterators and had tried using i., *i., (*i)., i->, *i->, (*i)-> and even using the & instead of *, but everything still came back with errors. I put it back to the way you suggested and the errors are stating "no match for operator=" (lines: 21, 44), "no match for operator==" (line: 23) and "no match for operator!=" (line: 44). There are a lot of "notes" but I figure those will disappear once the errors are fixed.

error: no match for 'operator=' (operand types are 'std::__cxx11::list<std::__cxx11::basic_string<char> >::iterator {aka std::_List_iterator<std::__cxx11::basic_string<char> >}' and '__gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >')

I have searched the web and find mention of using/not using const with the iterator depending on the case; however, since I do not see const in the error message, I assume that is not the problem.

I found mention of using the auto for the iterators; so I replaced the list<myStruct>::iterator and list<string>::iterator with auto and these were the messages I received:

||=== Build: Debug in TestStructure (compiler: GNU GCC Compiler) ===

C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\predefined_ops.h||In instantiation of 'bool __gnu_cxx::__ops::_Iter_equals_val<_Value>::operator()(_Iterator) [with _Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; _Value = const std::__cxx11::basic_string<char>]':

C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\stl_algo.h|120|required from '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const std::__cxx11::basic_string<char> >]'

C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\stl_algo.h|161|required from '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; _Predicate = __gnu_cxx::__ops::_Iter_equals_val<const std::__cxx11::basic_string<char> >]'

C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\stl_algo.h|3790|required from '_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator<char*, std::__cxx11::basic_string<char> >; _Tp = std::__cxx11::basic_string<char>]'

TestStructure.cpp|21| required from here

C:\Program Files (x86)\CodeBlocks\MinGW\lib\gcc\mingw32\5.1.0\include\c++\bits\predefined_ops.h|194|error: no match for 'operator==' (operand types are 'char' and 'const std::__cxx11::basic_string<char>')

=== Build failed: 1 error(s), 5 warning(s) (0 minute(s), 2 second(s)) ===

Tried putting const in front of auto, but still received the same error messages. Still checking sites. Any ideas from this point?

Thanks for you help
closed account (E0p9LyTq)
I was not able to get the code to appear in the box as yours did (I clicked the <> button that said code but did not seem to do anything).

When creating a new topic the format buttons don't work. When creating a reply or editing a post the format buttons work.

Old, well known problem. :)

Easy to add code tags, edit your post.
http://www.cplusplus.com/articles/jEywvCM9/
About using code tags: http://www.cplusplus.com/forum/articles/16853/

Try this (still untested, but rewritten)
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
struct myStruct
{
    string key;
    list<string> content;
    myStruct(string k, list<string> cnt) : key(k), content(cnt) {}
};

list<myStruct> MyList;

list<myStruct>::iterator i; // Also tried as list<string>
list<string>::iterator j;
string tkey, tcontent; // key and content to check for

// Test data
tkey = "a7b4";
tcontent = "this is a test";

// See if key exists
i = find(MyList.begin(), MyList.end(), tkey);
if (i != MyList.end())
{
    MyList.push_back(myStruct(tkey, tcontent));
}
// If yes, check if content exists
else
{
    j = find(i->content.begin(), i->content.end(), tcontent);
    // If no, add content to key
    if (j == i->content.end())
        i->content.push_back(tcontent);
}

// Display to check accuracy of storage
for (i = MyList.begin(); i != MyList.end(); i++)
{
    cout << i->key << endl;
    for (j = i->content.begin(); j != i->content.end(); j++)
        cout << " " << *j << endl;
}

Ok. Tried this and got the same error message and 5 warning messages with 1 new one.

TestStructure.cpp|22|error: no matching function for call to 'myStruct::myStruct(std::__cxx11::string&, std::__cxx11::string&)'

which seems to me to indicate it is having a problem with the list<string> content assignment.

And wouldn't line 20 become if (i == MyList.end()) to indicate it reached the end and not found it?

Thanks

NOTE:
I tried changing line 5 to:
myStruct(string k, string cnt) { key(k), content.push_back(cnt); }
The extra error above disappeared, but the 1 error and 5 warnings from before remained.

Last edited on
Okay, so I finally actually ran it.
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
45
46
47
48
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;

struct myStruct {
    string key;
    list<string> content;
    myStruct(const string& k, const string& cnt) : key(k) {
        content.push_back(cnt);
    }
};

int main() {
    list<myStruct> MyList;
    list<myStruct>::iterator i;
    list<string>::iterator j;
    string tkey, tcontent;

    // Test data
    tkey = "a7b4";
    tcontent = "this is a test";

    // See if key exists
    for (i = MyList.begin(); i != MyList.end(); i++)
        if (i->key == tkey)
            break;
    if (i == MyList.end()) { // doesn't exist
        MyList.push_back(myStruct(tkey, tcontent));
    }
    // If yes, check if content exists
    else {
        j = find(i->content.begin(), i->content.end(), tcontent);
        // If no, add content to key
        if (j == i->content.end())
            i->content.push_back(tcontent);
    }

    // Display to check accuracy of storage
    for (i = MyList.begin(); i != MyList.end(); i++)
    {
        cout << i->key << endl;
        for (j = i->content.begin(); j != i->content.end(); j++)
            cout << " " << *j << endl;
    }
}

Changing "string to "const string &" worked. I really appreciate this. I hope this helps anyone else who may need to use a similar setup without resorting to multimap.

Excellent help.

Thanks

Since memory is an issue, consider using forward_list instead of list. forward_list is a singly linked list, so it saves one pointer per node.
Topic archived. No new replies allowed.