How to add an element to a vector in a map - c++

Right now my code is looping through a text file and adding to a map the kgrams and characters that follow. The keys are strings and the values are vectors. But how do I add an element to the vector associated with the key?
Here is the code for adding that value, but it doesn't seem to be working.
for (int i = 0; i < wrapAround.length(); i++)
{
temp = i + order;
kgram[wrapAround.substr(i, temp)].add(temp++); //add value to the vector associated with key
}
I have an if statement later on to see if the values later on are in the map, and it never is true... I am not sure why.

The second argument to string::substr in C++ is length and not ending position.
Try accessing the k-gram like this instead: wrapAround.substr(i, order)

I'll leave the substring indexing up to you but to add items to a C++ vector you use .push_back() or .push_front():
kgram[..].push_back(temp++);

Related

How to order the elements of a map using its values if keys are same?

I have a situation where I have to store marks of some students in descending order. So created a map<marks,string>. As a map stores data in the form of heap, always highest mark will be on top. But the problem arises when I have same mark for two students and I have to then rank them on the basis of their name (Alphabetical order considering their name's first letter).
What I did: I separated the marks and names into another map this time with key as name and mark as value. And then printed the new map in the reverse way. And then continued from where I left in the old map. But this requires creation of extra map and involves lot of processing.
My question Is there a better way to do this?
You could create a map<marks, list<string> > or something similar to store all names for one mark there. Lists come with a sort method, so you can sort all lists that have more than one entry.
If you insert them all at a time, you can
create a list if the key is not present
append the name to the mark's list
iterate over all keys
sort the value if larger than 1
print.
What I would do is to have a map like this :
map<marks, vector<string>>
As this, each mark is binded to a sorted array of students. Everytime you want to insert a new student into a vector, you simply need to find the right index to keep your vector sorted (Dichotomic search is the fastest)
You can also use list<string> instead of vector
You may just use set<pair<mark, string>/*optional appropriate-comparator*/>. It'll sort using marks first, then names.
It'll still be O(log n) for sorted insertion contrary to sorted vector solution
Basically you need a Map that can store duplicate keys(int) in non-ascending order and values(string) in non-descending order.
I have a situation where I have to store marks of some students in descending order.
Use std::greater so that the keys will be stored in descending order:
std::map<int, string, std::greater<int> > m;
But the problem arises when I have same mark for two students.
Use Multimap instead of Map. Multimap stores duplicate keys and that is its specialty.
std::multimap<int, string, std::greater<int> > m;
I have to then rank them on the basis of their name (Alphabetical order considering their name's first letter).
Store the value of identical-keys in map in a vector > sort the vector > insert the sorted vector back into map.
Note that, inside multimap, you don't need to worry about changing the keys or its order. Values are the only ones whose order is going to be changed (that too only within same-valued-key).
Demo
multimap<int, string, greater<int> >:: iterator it = m.begin(), st; //Stores duplicate keys(marks).
vector<string> vec;
int lastKey = INT_MAX;
while(it != m.end())
{
if(it->first < lastKey)
{
//Sort the Names
sort(vec.begin(), vec.end());
for(int i = 0; i < vec.size(); i++){
st->second = vec[i];
st++;
}
st = it;
vec.clear();
}
vec.push_back(it->second); //Insert name
lastKey = it->first; //marks of last inserted name.
it++;
}
//Do same for the last(lowest valued key in map) key.
sort(vec.begin(), vec.end());
for(int i = 0; i < vec.size(); i++){
st->second = vec[i];
st++;
}

Vector of pairs to map

I have a little problem.
I have a vector of pairs patternOccurences. The pairs are <string,int>, where string is the pattern(name) and int the index where it appears. My problem is that patternOccurences has multiple pairs with the same .first(same pattern) but different int values.
For example: The vector has 10 entries. 5 of pattern "a" and 5 of pattern "b". all have different indices. Now i want to have a map (or something similar) so that i have a vector/list with each pattern(in my example "a" and "b") as a key and a vector of their indices as the value. The indices are in the different pairs in my vector of pairs and i want all indices for pattern "a" in a int vector as value for key "a".
I tried the following:
std::map<std::string,std::vector<int>> occ;
for(int i = 0;i<patternOccurences.size();i++){
if(occ.find(patternOccurences.at(i).first)==occ.end()){
occ[patternOccurences.at(i).first]=std::vector<int>(patternOccurences.at(i).second);
}
else{
occ[patternOccurences.at(i).first].push_back(patternOccurences.at(i).second);
}
}
patternOccurences is the vector of pairs and occ the desired map. First i check if there is already an entry for the string(pattern) and if not i create one with a vector as value. If there is already one I try to push_back the vector with the index. However it doesnt seem to be working right. For the first pattern i get a vector with 0 only as values and for the second there are only 3 indices which are right and the other ones are 0 as well.
I hope you can help me.
Kazoooie
You are calling the constructor for the vector in the wrong way:
std::vector<int>(patternOccurences.at(i).second);
This creates a vector with N default constructed elements, not a vector with one element with value N. You need:
std::vector<int>(1, patternOccurences.at(i).second);
That should fix the problem, but your code doesn't have to be that complicated. The following would work just fine:
for(int i = 0;i<patternOccurences.size();i++){
occ[patternOccurences.at(i).first].push_back(patternOccurences.at(i).second);
}
or with C++11, the even simpler:
for(auto& p:patternOccurences) {
occ[p.first].push_back(p.second);
}
What you are asking for already exists in STL and it's called std::multimap (and std::unordered_multimap).
Take a look here. Basically it's a map which allows more values to have the same key.
std::multimap<std::string, int> occ;
occ.insert(std::pair<std::string,int>("foo", 5));
occ.insert(std::pair<std::string,int>("foo", 10));
std::pair<std::multimap<std::string,int>::iterator, std::multimap<std::string,int>::iterator> group = occ.equal_range("foo");
std::multimap<std::string,int>::iterator it;
for (it = ret.first; it != ret.second; ++it) {
..
}
Change this statement
occ[patternOccurences.at(i).first]=std::vector<int>(patternOccurences.at(i).second);
to
occ[patternOccurences.at(i).first]=std::vector<int>(1, patternOccurences.at(i).second);

For statement find unique values

I am trying to find the unique values in the array num[], without functions, C++
Unique values in that an array with (3,5,3,4) would only find 3 unique values, the array comparing against itself. Size is the elements in the array(size 4 for the above array)
for ( k=0; k<size; k++){
for (i=k+1;num[k]!=num[i]&&i<size; i++) { // i = 1 don't want it to compare itself
if ( i+1 == size) {
unique++;
}
}
}
The problem I keep getting 1 or 0 unique values depending on what I do, any suggestions in the right direction would be helpful. Edit: added i=k+1 to second FOR (still getting 1 short though, maybe it is skipping the last iteration or first)
You're trying it without functions, but are you willing to use data structures? You could use a hash table. The keys are the values, and the values are the number of appearances, then you can count the number of hashes to find the number of unique items.
If you're using the brute force method, you'll need to compare each of element with every other element. Carefully check your code to see if it's doing that.
Alternatively, for a much faster method, use a std::set - keep adding elements into the set and find out the size of the set in the end. Duplicate elements are automatically discarded.
Thanks for everyone's answers, i = k+1 (previous loop was needed) and since the last iteration had nothing to compare to you had to check for that and add one.
for ( k=0; k<size; k++){
for (i=k+1;num[k]!=num[i]; i++) { // i = 1 don't want it to compare itself
if ( i+1 == size)
number++;
}
if(k+1==size)
number++
}

Adding to middle of std::vector

Is there a way to add values to the middle of a vector in C++? Say I have:
vector <string> a;
// a gets filled up with "abcd", "wertyu", "dvcea", "eafdefef", "aeefr", etc
and I want to break up one of the strings and put all of the pieces back into the vector. How would I do that? the strings I break can be anywhere, index = 0, somewhere in the middle, or index = a.size() - 1.
You can insert into a vector at position i by writing
v.insert(v.begin() + i, valueToInsert);
However, this isn't very efficient; it runs in time proportional to the number of elements after the element being inserted. If you're planning on splitting up the strings and adding them back in, you are much better off using a std::list, which supports O(1) insertion and deletion everywhere.
You can do that, but it will be really slow:
int split = 3; // where to split
a.insert(a.begin()+index, a[index].substr(0, split));
a[index+1] = a[index+1].substr(split);
in this example dynamically find the vector middle and insert new element.
std::vector <std::string> friends;
friends.push_back("Ali");
friends.push_back("Kemal");
friends.push_back("Akin");
friends.push_back("Veli");
friends.push_back("Hakan");
// finding middle using size() / 2
int middleIndexRef = friends.size() / 2;
friends.insert(friends.begin() + middleIndexRef, "Bob");

Fast way to pick randomly from a set, with each entry picked only once?

I'm working on a program to solve the n queens problem (the problem of putting n chess queens on an n x n chessboard such that none of them is able to capture any other using the standard chess queen's moves). I am using a heuristic algorithm, and it starts by placing one queen in each row and picking a column randomly out of the columns that are not already occupied. I feel that this step is an opportunity for optimization. Here is the code (in C++):
vector<int> colsleft;
//fills the vector sequentially with integer values
for (int c=0; c < size; c++)
colsleft.push_back(c);
for (int i=0; i < size; i++)
{
vector<int>::iterator randplace = colsleft.begin() + rand()%colsleft.size();
/* chboard is an integer array, with each entry representing a row
and holding the column position of the queen in that row */
chboard[i] = *randplace;
colsleft.erase(randplace);
}
If it is not clear from the code: I start by building a vector containing an integer for each column. Then, for each row, I pick a random entry in the vector, assign its value to that row's entry in chboard[]. I then remove that entry from the vector so it is not available for any other queens.
I'm curious about methods that could use arrays and pointers instead of a vector. Or <list>s? Is there a better way of filling the vector sequentially, other than the for loop? I would love to hear some suggestions!
The following should fulfill your needs:
#include <algorithm>
...
int randplace[size];
for (int i = 0; i < size; i ++)
randplace[i] = i;
random_shuffle(randplace, randplace + size);
You can do the same stuff with vectors, too, if you wish.
Source: http://gethelp.devx.com/techtips/cpp_pro/10min/10min1299.asp
Couple of random answers to some of your questions :):
As far as I know, there's no way to fill an array with consecutive values without iterating over it first. HOWEVER, if you really just need consecutive values, you do not need to fill the array - just use the cell indices as the values: a[0] is 0 and a[100] is 100 - when you get a random number, treat the number as the value.
You can implement the same with a list<> and remove cells you already hit, or...
For better performance, rather than removing cells, why not put an "already used" value in them (like -1) and check for that. Say you get a random number like 73, and a[73] contains -1, you just get a new random number.
Finally, describing item 3 reminded me of a re-hashing function. Perhaps you can implement your algorithm as a hash-table?
Your colsleft.erase(randplace); line is really inefficient, because erasing an element in the middle of the vector requires shifting all the ones after it. A more efficient approach that will satisfy your needs in this case is to simply swap the element with the one at index (size - i - 1) (the element whose index will be outside the range in the next iteration, so we "bring" that element into the middle, and swap the used one out).
And then we don't even need to bother deleting that element -- the end of the array will accumulate the "chosen" elements. And now we've basically implemented an in-place Knuth shuffle.