I have a vector of pairs, which is empty at the beginning. I implemented a custom insert and remove method, and I would also like to be able to assign NULL to certain elements, but I can't because it's not a pointer to pair.
If I try to illustrate it more specifically - given a vector V
std::vector< std::pair<A,B> > V;
neither
V.assign(number,NULL);
nor
V[n]=NULL;
would work.
I need to do this to check if there already is an element saved in a certain slot. Is there anywork around or should I just create another vector of booleans to save wheter a certian slot is full or not?
NOTE: I know any kind of map would solve it elegantly, but it has to be a vector.
I think solution with map would be optimal in your case:
std::map<int, std::pair<A, B> > M;
Then you can do
M.erase(M.find(number))
To NULL-ify to the element.
If I had to do it I would do something like
vector< pair< pair<A,B> ,int > >V , V[i].second can be 0 or 1 depending whether the element
pair has to be NULL or not.This if if you want to mark the pair NULL but still keep it for refernece.Otherwise use map as Alex1985 said.
I advise you to look at boost::optional
boost::optional< std::vector< std::pair<A,B> > > V;
if (V) {
// V was initialized
} else {
// wasn't initialized
}
documentation examples: http://www.boost.org/doc/libs/1_54_0/libs/optional/doc/html/boost_optional/examples.html
Use shared_ptr as the second type in the pair.
std::vector< std::pair<A,std::shared_ptr<B> > > V;
V.assign(number, std::shared_ptr<B>());
V[n] = std::shared_ptr<B>();
V[n] = std::shared_ptr<B>(new B());
if (V[n].get() == NULL) { /* process empty here */ }
The shared_ptr class was introduced to C++ in TR1, and is part of the C++11 specification. It works well with standard containers because it
Related
The way to insert a pair in a map is that:
std::map<char,int> mymap;
// first insert function version (single parameter):
mymap.insert ( std::pair<char,int>('a',100) );
but now I'm trying to insert this in a map:
map<pair<int,int>, int> map1; //(pair is the key and int is a value)
I tried this:
pair<int,int> p;
p.first = 5;
p.second = 20;
map1.insert(pair<int,int>,double> (p,0));
So, how I can do it?
There are so many possibilities for this. You may choose any of the below which suits you better.
Using make_pair
map<pair<int,int>, int> m;
m.insert(make_pair(make_pair(5,20), 0));
Using curly braces
map<pair<int,int>, int> m;
m.insert({{5,20}, 0});
Declaring a C++ Pair first
pair<int,int> p(5,20);
map<pair<int,int>, int> m;
m.insert(make_pair(p, 0));
You can define and fill pairs manually if you want, but it's more common and idiomatic to use make_pair, or (since C++17) the deduction guides for pair:
map1.insert(std::make_pair(std::make_pair(5,20),0));
map1.insert(std::pair{std::pair{5,20},0}); // C++17 or later
First, if you are constructing the key while inserting, you may want to use emplace instead, since it will construct the key and value in place and is also better equipped to forward the arguments passed to it without explicit construction. So your first example would be simplified to
mymap.emplace('a', 100);
while your second example will surely work as
map1.emplace(std::piecewise_construct, std::forward_as_tuple(5, 20), std::forward_as_tuple(0));
and from C++17 onwards may also work as
map1.emplace(5, 20, 0);
See for examples here and here
I have a vector which I use for an observer pattern to register the name and pointer: a registration list.
I want to unregister an observers from the vector pair.
I am not sure how to proceed, I tried this but does not compile at all.
vector < pair<string , Observer* > > destination;
void subject::unregisterObservers(LogObserver* obsIfP)
{
vector <pair<string, LogObserverIf*> > ::iterator it;
for(it = observers.begin(); it != observers.end(); it++)
{
if((*it).second == obsIfP)
{
remove(observers.begin(), observers.end(), (*it).first);
break;
}
}
}
How do I remove elements from the vector based on one of the values inside a pair element?
You should use vector::erase() instead.
for(it = observers.begin(); it != observers.end(); it++)
{
if(it->second == obsIfP)
{
observers.erase(it);
break;
}
}
There's a few issues with your current code.
std::remove will find and move elements equal to the given value to the end of the container. It then returns the iterator pointing to the end of the non-removed range in the vector. To have them completely removed would require vector.erase with the iterator returned from the remove algorithm.
The erase-remove idiom:
v.erase( remove( begin(v), end(v), value ), end(v) )
Note, your code gives a string as value and will not compile, since elements in the vector are pair< string, Observer* > and the algorithm can't compare between the two.
Erasing while iterating over the same range is dangerous, since you may invalidate the iterators of the first loop.
Using algorithms with predicates:
Depending on the size of the vector, it may just be simpler (and even faster) to generate a new vector.
typedef pair<string, Observer*> RegPair;
vector<RegPair> new_observers;
new_observers.reserve( observers.size() ); // To avoid resizing during copy.
remove_copy_if( begin(observers), end(obervers), std::back_inserter(new_observers),
[obsIfP]( const RegPair& p ) -> bool
{ return p.second == obsIfP; } );
observers = std::move(new_observers);
// --- OR THIS
observers.erase( remove_if( begin(observers), end(observers),
[obsIfP]( const RegPair& p ) -> bool
{ return p.second == obsIfP; } ),
end(observers) );
Removing an element in the middle of a vector will cause all the following elements to be moved back one index, which is essentially just a copy anyway. If more than one element has the observer pointer, your initial code would have to move these elements more than once, while this suggestion always has a worst case of O(N), where the elementary operation is a copy of the pair element. If better performance than O(N) is required, you'll have to arrange your observers with std::map< string, Observer* > or perhaps boost::bimap which lets you use both pair values as keys.
The difference between remove_if and copy_remove_if would be the preserving of order. remove_if may swap elements and place them elsewhere in order to get the removed element to the end-range. The copy_remove_if will simply not copy it over to the new container, so order is preserved.
If you're not using c++11, the lambda wont work and you'll have to hand code the loop yourself.
I need to find an element in a vector<pair<int, float>> and increase the second value.
I tried an approach.
template <typename K, typename V>
struct match_first {
const K _k; match_first(const K& k) : _k(k) {}
bool operator()(const pair<K, V>& el) const {
return _k == el.first;
}
};
Eg to use.:
vector< pair<int, float> > vec;
vec.push_back(make_pair(2, 3.0));
vec.push_back(make_pair(3, 5.0));
vec.push_back(make_pair(1, 1.0));
vector< pair<int, float> >::iterator it = find_if(vec.begin(), vec.end(), match_first<int, float>(3));
if (it != vec.end()) {
it->second += 9;
}
There is a more efficient way of accomplishing this task?
A map seems more natural:
#include <map>
int main()
{
std::map<int, float> m;
m.insert(std::make_pair(2, 3.0));
m.insert(std::make_pair(3, 5.0));
m.insert(std::make_pair(1, 1.0));
auto it = m.find(3);
if (it != m.end()) {
it->second += 9;
}
}
It will also be faster because lookup is O(log(n))
You can reach the same complexity with a vector of sorted pairs by using std::lower_bound (or std::equal_range if keys can be repeated)
It depends on your constrains. If you have the unique key (the first element) you can use std::map<K,V> to hold your objects. Then increasing it is easy. If V has a default constructor initializing it to zero, you can even skip adding new elements and just increment (I am not sure it will work with ints through).
std::map<K,V> data;
data[key] = data[key] + 1;
the [] operator used for non-existent key will create the object for you using its default constructor. To just access data use at or find methods.
extending sehe's answer: You can use std::multimap in the same way if you may have duplicate keys. This container also keeps the <K,V> pair in sorted order(keys) so binary search approach obviously speed up things.
There is no exact answer to your question: it depends.
My first answer is: use std::find_if (available in <algorithm>, part of the C++ Standard Library), then profile your code. If the search turns out to be a bottleneck worthy of concern, then try another approach.
Beware of using a std::map, as it will sort the pairs by their first component (that is, the insertion order will be lost). In addition, it will not allow you to store two pairs with the same first component.
As others have mentioned, you can work around this caveats (if they are indeed caveats to your problem), but, like I mentioned before, it would only be worth your while if you demonstrate first that the search turned out to be a bottleneck after using the standard algorithms.
Assume I have a nested map of type pointer. Then is there a single line statement to insert into the nested map,
map<int, map<int, int> >* nestedMap;
Currently I am doing this in 2 steps. First creating innermap and then insert into outer map as below,
nestedMap->insert(make_pair(int, map<int, int>)(int, innermap));
If the map is not pointer type, then i can insert easily like this,
nestedMap[int][int] = int;
Is there any simple ways for inserting into nested map of type pointer ?
thanks
Prabu
map::operator[] automatically creates the key/value pair if it doesn't exist.
(That's why it's not const!)
So you don't need to create the inner map manually.
If you want to avoid creating the pair automatically, then use map::find() or map::at().
I believe the simplest one-liner is:
(*nestedMap)[int][int] = int;
If i understand your question properly, you can actually use reference instead of pointer. You are not having issue with nested map, instead your outter map.
See below code, is what you want?
map<int, map<int, int> >* nestedMap = new map<int, map<int, int> >;
map<int, map<int, int> > &nestedMapAlais = *nestedMap;
nestedMapAlais[1][2] = 3;
access the operator[] via ->:
nestedMap->operator[](5)[6] = 7;
This is analogous to
nestedMap[5][6] = 7;
if nestedMap is not a pointer.
Note that in neither case do you have to explicitly insert a map.
I have this new class Seq that inherits vector and has some additional features. I can use all methods of vector with Seq.
Having this data structure:
Seq< vector<int> > sweepEvents;
I want to have a function that takes an element vector edge search for it in sweepEvents and returns the iterator to the position of the found element in sweepEvents (if and only if edge is found) and the iterator to the last elements of the vector (if and only if edge is not found).
Then I want to work with this iterator, in that I want to compare the elements from the prev and the next position of iterator.
I have the following function for founding and returning the iterator:
Seq< vector<int> >::iterator QSweep::insertSweepEvents(edge_t edge,int currentDim){
int changePosition;
int found=0;
for (int i=0;i<currentDim;i++){
if (edge[0]==sweepEvents[i][1]){
changePosition=i;
found=1;
return sweepEvents.begin()+changePosition;
}
}
if (found==1){
sweepEvents.rep().insert(sweepEvents.begin()+changePosition,edge);
sweepEvents.rep().erase(sweepEvents.begin()+changePosition+1);
}
else{
sweepEvents.rep().insert(sweepEvents.end(),edge);
}
return sweepEvents.end()-1;
}
I then call this iterator in the main function. I actually tried but it does not compile and I do not know what syntax to use other than this:
int main(){
Seq< vector<int> > sweepEvents;
vector<int> edge;
//.....initialize sweepEvents and edge
//declare iterator but not working
Seq< vector<int> >::iterator comparePosition;
//not working neither
comparePosition=insertSweepEvents(edge,sweepEvents.size());
}
Any idea on how I should correctly call the iterator? I see it does not work as an integer index from an array?
Is Seq< vector< T > >::iterator defined in your Seq class?
Making the parameter of the template 'vector' does not imply that exists the type Seq< vector< int > >::iterator
What compilation error ? How is defined Seq<X>::iterator ?
#include <vector>
template<typename T>
struct Seq
: public std::vector<T>
{ };
typedef Seq< std::vector<int> > SeqI;
SeqI::iterator insertSweepEvents(SeqI &s)
{
return s.begin();
}
int main()
{
SeqI s;
SeqI::iterator e = insertSweepEvents(s);
}
This works fine.
Something illogical in your code. See my comments:
int found = 0;
for (int i=0;i<currentDim;i++){
if (edge[0]==sweepEvents[i][1]){
changePosition=i;
found=1;
// This place is one, where we assign 1 to found, and we do return after that (maybe you want do break/?)
return sweepEvents.begin()+changePosition;
}
}
if (found==1){ // as you see we reach this place only when found == 0
A little sidenote:
After a vector is changed, especially when appended to or inserted in, iterators to it become invalid. That's due to the fact that the vector tries to allocate a minimally sized contiguous block of memory for it's internal data, while at the same time it tries to minimize the number of times it needs to allocate a new, bigger chunk. So the data may move through memory, so iterators to it before a push are no longer valid after it.
Another little note:
You can find the difference between two iterators by using std::difference( it1, it2 ). You can re-apply that difference by using std::advance( it1, d ).
A third little note:
You seem to have a 'return' statement inside the for-loop, but the rest of the code uses variables that are set only when returning...