-2

Code worked on:

#include <algorithm>
#include <list>
#include <vector>

class key_value_sequences {
public:

    int size(int key);
    int * data(int key);
    void insert(int key, int value);

private:
    list< pair<int, vector<int> > > myList;

}; // class key_value_sequences

#endif

void key_value_sequences::insert(int key, int value){
    list< pair<int, vector<int> > >::iterator it;
    for(it = myList.begin(); it != myList.end(); ++it){
        if (it->first == key){
            it->second.push_back(value);
            return;
        }
    }
    vector<int> v;
    v.push_back(value);
    myList.push_back(make_pair(key, v));
    return;
};

int * key_value_sequences::data(int key){
    list< pair<int, vector<int> > >::iterator it;
    for(it = myList.begin(); it != myList.end(); ++it){
        if (it->first == key){
            return (it->second);
        }
    }
    vector<int> v;
    return v;
};

int key_value_sequences::size(int key){
    list< pair<int, vector<int> > >::iterator it;
    for(it = myList.begin(); it != myList.end(); ++it){
        if (it->first == key){
            return it->second.size();
        }
    }
    return -1;
};

I am getting errors for template arguments, and can't figure out why. It looks like this line

std::list< pair<int, vector<int> > > myList;

is throwing errors

 error: template argument 1 is invalid
 std::list< pair<int, vector<int> > > myList;
                                  ^
 error: template argument 2 is invalid
 error: expected unqualified-id before ‘>’ token
 std::list< pair<int, vector<int> > > myList;
                                    ^

I can't figure out why.

I'm also stuck with errors

/usr/include/c++/5/bits/stl_algobase.h:840:58: error: no type named ‘value_type’ in ‘struct std::iterator_traits<std::vector<int> >’
   typedef typename iterator_traits<_II2>::value_type _ValueType2;
                                                      ^
/usr/include/c++/5/bits/stl_algobase.h:845:9: error: no type named ‘value_type’ in ‘struct std::iterator_traits<std::vector<int> >’
         && __are_same<_ValueType1, _ValueType2>::__value);
         ^

The instantiation of the iterator is:

list<pair<int, vector<int>>>::iterator it;

Edit trying out vector hashtable:

   class key_value_sequences {
public:

int size(int key);


int* data(int key);


void insert(int key, int value);

private:
    vector<list<pair<int,int>>> hash_table;
    list<pair<int, vector<int>>>::iterator it;

    int hash(int value)
    {
        return abs(value%static_cast<int>(hash_table.size()));
    }

}; // class key_value_sequences

#endif // A3_HPP

void key_value_sequences::insert(int key, int value){

          list<pair<int,int>> &collisionlist = hash_table[hash(key)];


          for (std::pair<int,int> &test: collisionlist)
          {
              if (key == test.first)
              {
                  test.second = value; // update existing
                  return;
              }
          }

          collisionlist.push_back(pair<int,int>(key, value));
};

int* key_value_sequences::data(int key){

    for(it = hash_table.begin(); it != hash_table.end(); ++it){
        if (it->first == key){
            return &(it->second[0]);
        }
    }
    return nullptr;
};

int key_value_sequences::size(int key){

    for(it = hash_table.begin(); it != hash_table.end(); ++it){
        if (it->first == key){
            return it->second.size();
        }
    }
    return -1;
};
Gman
  • 83
  • 1
  • 1
  • 7
  • 1
    What you are looking for is a `std::map`. – Sam Varshavchik Oct 15 '16 at 16:30
  • BTW, you should use a different name than `string`. To find out why, research [string](http://en.cppreference.com/w/cpp/string/basic_string) in your favorite C++ reference. – Thomas Matthews Oct 15 '16 at 16:33
  • Please post the definition of `string`. – Thomas Matthews Oct 15 '16 at 16:34
  • You need to have a data structure associated with the class to be able to pull any values that you add to it. Instantiating the list within the insert function does nothing for the class, as the data would be lost upon exiting the function. Add a private list, and at that point the data function would just be able to iterate over the list and print the data. –  Oct 15 '16 at 17:42
  • @MattGalaxy so just move `std::list> myList;` to the private, and leave the push_back line? I supposed I should make a loop somehow for the push_back, so it does more than just once though. – Gman Oct 15 '16 at 17:49
  • Correct. Furthermore, the `size` function for a `list` does not take any arguments since a `list` has a static size. I'm going to edit my answer a little to provide some more insight with issues with your code. –  Oct 15 '16 at 17:57
  • @Gman aha! Since it doesn't appear you have [`using namespace std`](http://stackoverflow.com/questions/18914106/what-is-the-use-of-using-namespace-std) within your code, you're only referencing the standard library with respect to the `list`... but you also need to reference the standard library with respect to the `pair` construction & `vector` within the `pair`. For example- `std::list< std::pair > > myList;` –  Oct 17 '16 at 00:56
  • @MattGalaxy Idk how I lost `using namespace std`, but adding that in fixed a few errors, and I've fixed all others except the bottom two I just added to op – Gman Oct 19 '16 at 19:29
  • @Gman are you using my implementation? If so, can you edit into the OP the line that instantiates the iterator? You want to make sure you're specifying the correct types as well as the correct number of types required for the template of each standard library reference. It should look like this: `list< pair > >::iterator it;` –  Oct 19 '16 at 19:41
  • @MattGalaxy that is what it looks like, minus the spacing between the between the `>>` signs, though changing the spacing makes no difference. I tried making it a private as well, but to no avail. – Gman Oct 19 '16 at 19:48
  • @Gman - I don't mean to be a bother, but when I attempt to compile my answer below & there is no spacing between the nested template arguments~ I get an error. Different error, but an error nonetheless. I just noticed my answer doesn't have `#include `- this might solve the error. –  Oct 19 '16 at 19:56
  • @MattGalaxy I initially had `#include `, but took it out because it makes no difference, and also added spaces to match your example, but still no luck. I just can't figure it out. – Gman Oct 19 '16 at 21:18
  • @Gman any chance you would be willing to share your code (or the code you've updated since this question) with me in the OP or pastebin? I'd love to help you solve this because I'm really curious as to where this error is coming from. –  Oct 19 '16 at 23:01
  • @MattGalaxy how does pastebin work? I'd prefer to keep it more private with my entire code. – Gman Oct 20 '16 at 14:51
  • @Gman you could create an unlisted paste & share the link here- but I understand the necessity for privacy. The only thing I can suggest is to try and add as much of the code you've added since the beginning of this question to the OP- or put on your bug hunting glasses since I presume the error is caused by a typo or incorrect instantiation of an iterator. –  Oct 20 '16 at 15:00
  • @Gman found it. On line 33 your third argument for `equal` is a vector when it should be a pointer to the beginning of the vector - `A.data(k).begin()`. I'm assuming you have `#include ` –  Oct 20 '16 at 17:12
  • @MattGalaxy Thank you! That fixed those errors for my code and I could get it to pass. Out of curiosity, is there a way to go about keeping it as a vector, and change something else? – Gman Oct 20 '16 at 17:40
  • @Gman I believe so! `vector`s support [relational operators](http://www.cplusplus.com/reference/vector/vector/operators/)- so you can try using `==` for comparing as opposed to using `equal`. –  Oct 20 '16 at 17:46
  • @MattGalaxy anything without changing the equal arguments perhaps? – Gman Oct 20 '16 at 17:55
  • @Gman I edited my answer and denoted changes with `//******`~ I changed the `data` function so that it returns a pointer to the beginning of the vector (essentially returning an array). This should allow you to keep the third argument in `equal` as `A.data(k)` ... sorry about that! I believe your original data function was specified to return a pointer, but I changed it :) hope it helps! –  Oct 20 '16 at 18:06
  • @MattGalaxy Lol I actually wrote a note down for that to make sure I didn't change that in my code, but ended up going from pointer to vector just as you did. Changing it back solves that silly issue. Thanks a bunch! – Gman Oct 20 '16 at 18:26
  • @MattGalaxy using this implementation, is the list sorted by key? I'm trying to make it a bit more efficient, but getting stuck because it seems as though it would need to be ordered by key so I could do something like binary search rather than linear. – Gman Oct 20 '16 at 21:05
  • @Gman no. but a `list` has a `sort()` member function. I tested the functionality & it successfully sorts the entries by their `key` (aka `first` member of the `pair`). Just add `myList.sort()` after you `push_back` a new `pair` at the end of the `insert` function. –  Oct 20 '16 at 21:47
  • @MattGalaxy the sorting works just grand, but my insert takes forever to process a lot of entries, and runs O(n). Is there a way to speed it up? I'd like to use a hashtable, but I think to do that it would need to change it from list of vectors to vector of list? – Gman Oct 21 '16 at 20:52
  • @Gman: naturally, you could implement a [`binary search`](http://www.cplusplus.com/reference/algorithm/binary_search/) pattern in place of the `for` loop iteration I've specified in order to achieve O(log(N))- as you've suggested previously with regard to implementing the sort function. I'll edit my answer to my attempt at the new `insert` function :) –  Oct 21 '16 at 21:14
  • @Gman: While I linked to the `algorithm` ref to `binary_search`- it actually appears to be useless since it only returns a `bool` value. In my (your) implementation- it's important to retain the index so you can update the `vector` within the `list`... swapping `vector` & `list` doesn't speak "optimization" for me- so you should focus on replacing the `for` loop. –  Oct 21 '16 at 21:35
  • @Gman: Also, if your intention was to use a `hash` then you would've agreed to the `multimap` implementation. But since you seem to restrict yourself to `vector` & `list`~ you have an issue with access time since you need to calculate an index either way. –  Oct 21 '16 at 21:39
  • @MattGalaxy I updated op with my mess of an attempt to create hashtable with a vector, but it does not work properly, especially having trouble with operators `!=` now. – Gman Oct 22 '16 at 17:01

3 Answers3

1

Tried adding as much detail as I could in the comments, but this successfully passed all tests on my end. While I mentioned I reduced the original copy constructor from O(keys.length + vals.size) to just O(vals.size)- I lied.

resize() is linear in the length of the vector- so it's best to leave that alone.

 #include <iostream>
 #include <vector>
 #include <list>

 using namespace std;

 class key_value_sequences{
    public:
        int size(int key);
        int * data(int key);
        void insert(int key, int value);
        key_value_sequences(){};                               //ctor
        key_value_sequences(const key_value_sequences &_rhs); //[heli]coptor
        ~key_value_sequences(){};                            //dtor
    private:
        vector <vector<int> *> keys;
          list <vector<int>  > vals;
};

key_value_sequences::key_value_sequences(const key_value_sequences &_rhs){
    keys.resize(_rhs.keys.size());         //resize new kvs key vector to old size
    auto it = _rhs.vals.begin();

    while (it != _rhs.vals.end()){
        vals.push_back(*it);            //push back value vector to list
        keys[(*it)[0]] = &vals.back(); //use the prepended key value of value vector
        ++it;                         //            to reestablish ref in key vector
    }
}

void key_value_sequences::insert(int key, int value){
    if (key > -1 && key + 1 > keys.size()){    //if key index is valid & > key vector size
        keys.resize(key+1, new vector<int>);  //resize the vector to make room

        vector<int> v;
        vals.push_back(v);                 //push back new value vector to list
        vals.back().push_back(key);       //create key @ front of list for the [heli]coptor
        vals.back().push_back(value);    //push back initial value
        keys[key] = &vals.back();       //update reference in key vector
    }
    else if (key > -1){
        keys[key]->push_back(value); //index already exists, push back value to value vector
    }

    return;
}

int * key_value_sequences::data(int key){
    if (key + 1 > keys.size() || key < 0){
        return nullptr;
    }
    else{
        return &keys[key]->at(1);   //if index is valid: return second element of value vector
    }                              //in order to account for the prepended key
}

int key_value_sequences::size(int key){
    if (key < 0 || keys[key]->empty() || key + 1 > keys.size()){
        return -1;
    }
    else{
        return keys[key]->size() - 1; //if index is valid: return size - 1 to account for key
    }
}
  • The OP should have a unique key when using `std::map` or `std::set`. A lot of the pairs have 0 as they key. – Thomas Matthews Oct 15 '16 at 16:31
  • @ThomasMatthews - after looking into the definition a little more, it appears that it assumes one mapped value per key. I've edited my answer to indicate what I had intended to suggest. –  Oct 15 '16 at 16:40
  • @MattGalaxy what is the difference between map and unordered maps? I've used maps before so I think I have a bit better understanding of how I'd implement that. – Gman Oct 15 '16 at 16:41
  • @Gman maps actually sorts the containers, so you would then be able to iterate over them while expecting to know what the next value may be. For example, if you have keys '0' - '1' - & '2', then they would be organized in that order. As opposed to an unordered map.. where the container is added in the order you added it in, such as pushing back to a vector. –  Oct 15 '16 at 16:43
  • According to the `list::insert` method, the first parameter is the position in the list to insert before. So the OP is inserting values at the front of the list, except for 1. – Thomas Matthews Oct 15 '16 at 16:44
  • @Gman I've edited in my implementation to hopefully reduce the amount of times you would need to iterate over the list. In this version of my code the list has a vector associated with its key- allowing you to easily retrieve all the data as well as the size of the container corresponding to the key. –  Oct 15 '16 at 18:50
  • Thank you @MattGalaxy. I have fixed my size to look like – Gman Oct 15 '16 at 19:34
  • @MattGalaxy I edited op to show what I've fixed for size function. I understand this only returns size of list, not actual size of sequence for a given key. I also just realized I completely missed the other comment you made with the much larger example. I'm going to work through that to see how that works. Thanks – Gman Oct 15 '16 at 19:41
  • @Gman - I'm more than happy to help, and I'd love to clarify any questions you may have with my code. If you look at the member functions for the [`list`](http://www.cplusplus.com/reference/list/list/) container, you'll see that there is no `getNext()` function. You're almost there though! aatwo's and my code examples serve as perfect examples as to how to iterate through a list. –  Oct 15 '16 at 20:08
  • @MattGalaxy I'm trying to implement similar to your example, but keep getting template argument errors for `list< pair > > myList;` and out of scope for pair. Any idea what is causing this? – Gman Oct 16 '16 at 18:28
  • @Gman could you edit the exact error & the block of code that's causing it into the OP so I can take a better look please? :) –  Oct 16 '16 at 22:22
  • @MattGalaxy this brings up a segmentation fault(core dumped) – Gman Oct 23 '16 at 23:14
  • @Gman: lol. Okay I reverted the post back to a singular vector then. Let me know if that works. –  Oct 23 '16 at 23:16
  • Looks like that solves the segmentation problem, but fails objective.. Hmm – Gman Oct 23 '16 at 23:24
  • @Gman: I reverted the post back to the list of vectors (that had given a segmentation fault) except I replaced `push_back` with `emplace_back`- give this a try? Also, I'm not sure what you mean by objective & it's important to note this must be compiled with the `-std=c++11` flag. Any chance you can step through it with a debugger to see where the seg fault is occurring? –  Oct 23 '16 at 23:32
  • @MattGalaxy It doesn't seem to utilize key and values correctly, but I'm trying to figure out why – Gman Oct 23 '16 at 23:32
  • @MattGalaxy that still causes the segmentation fault. I don't currently have a debugger. Do you have any you recommend? – Gman Oct 23 '16 at 23:36
  • @MattGalaxy "Standard input empty"? – Gman Oct 23 '16 at 23:46
  • @Gman: https://chatstep.com/# - password is `stackoverflow` Just makes it easier to chat rather than commenting. –  Oct 23 '16 at 23:48
  • @MattGalaxy I'm in – Gman Oct 23 '16 at 23:55
0

To answer the title of your question, you can use the push_back methods of std::list and std::vector to put items into those containers.

The items will stay in the container until the container is deleted, the items are deleted or your program stops executing.

To find items in your containers, you can search using a loop. The std::list and std::vector both support iterators for iterating through the container. Items in a std::vector can be retrieved using array syntax.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
0

It sounds to me like you need a multimap. A map is a container that allows you to insert key / value pairs, where keys can be used to look up values. A multimap allows you to have multiple values associated with a single key.

For example:

    std::multimap<int, int> myMap;

    myMap.insert( std::make_pair( 0, 8 ) );
    myMap.insert( std::make_pair( 0, 5 ) );
    myMap.insert( std::make_pair( 0, 7 ) );
    myMap.insert( std::make_pair( 1, 15 ) );

    // equal_range() returns a pair of iterators pointing to the first item
    // in the list for the specified key, and one past the final item containing
    // the key.
    auto searchResultIteratorPair = myMap.equal_range( 0 );

    // Print out the values found
    for( auto it = searchResultIteratorPair.first; it != searchResultIteratorPair.second; it++ )
    {
        std::cout << "Value: " << it->second << std::endl;
    }

If my assumption was wrong and you really did want to use a list / vector, then you would need to create them as a list / vector of pairs. Then to find items you would iterate the entire list and check each pair to see if it matched your criteria.

For example:

std::list< std::pair<int, int> > myList;

    myList.push_back( std::make_pair( 0, 8 ) );
    myList.push_back( std::make_pair( 0, 5 ) );
    myList.push_back( std::make_pair( 0, 7 ) );
    myList.push_back( std::make_pair( 1, 15 ) );

    int searchValue = 0;
    for( auto it = myList.begin(); it != myList.end(); it++ )
    {
        if( it->first != searchValue )
            continue;

        std::cout << "Value: " << it->second << std::endl;
    }
aatwo
  • 948
  • 6
  • 12
  • FYI, the `0` in `insert(0,5)` is the position, not a value. – Thomas Matthews Oct 15 '16 at 16:46
  • @aatwo I can actually only use list/vector. How would this differ from your example? – Gman Oct 15 '16 at 16:48
  • @ThomasMatthews I realize now I would like to only use list/vector, since map/unordered_map implementation is a little too straight forward, and I'm trying to work with a different structure. – Gman Oct 15 '16 at 16:49
  • @aatwo I added what I've written to the original post. I was thinking I put the for loop inside the data class? – Gman Oct 15 '16 at 17:38