Sorting a std::map - c++

I have defined a map like this
typedef std::vector< int > aVector;
typedef std::map< int, aVector > aMap;
aMap theMap;
Assume that the map finally contains some elements like this
10 [0 3 7] size=3
12 [40 2 30 3 10] size=5
20 [5 10] size=2
25 [6] size=1
I want to sort on the size of the vector (e.g theMap->second.size()). So the result will be
5 3 2 1
What is the fastest way to do that? The basic idea is to push the sizes on another vector and then call sort(), like this
aVector v, sorted;
aMap::iterator it = theMap.begin();
for (; it != theMap.end(); ++it) {
v.push_back(it->second.size());
}
// using std sort!!
Is there any better option?

Why not putting the vector as the key and using your custom key comparison function / functor which would compare the keys sizes ?
You can see examples of this in http://www.cplusplus.com/reference/map/map/map/ ?
I haven't acces to a C++ compiler right now, but it would be something like:
#include <map>
struct aComparisonStruct {
bool operator() (const aVector& lhs, const aVector& rhs) const {
return lhs.size > rhs.size;
}
};
int main () {
typedef std::vector<int> aVector;
typedef std::map<aVector, int, aComparisonStruct> aMap;
// Use your map
return 0;
}
There is a problem though : You can't use the property of single key presence anymore, and you wouldn't be able to add multiple times the same vector. Maybe another implementation would be more appropriate ?
Also, it would be definitely better to use pointers as keys, but since I can't compile, I don't want to mix up pointers and references and give you something that wouldn't probably work.

There is a very common task when you need to have quick lookup through std::map or std::hash_map and to manage it with some specific order. In this situation you may use kinda "index" collection over your main collection:
aMap theMap;
std::map<size_t, std::list<aMap::iterator> > sizes;
// add item
auto r = theMap.insert(key, std::vector<int>());
if (!r->second)
{
sizes[r->first->second.size()].remove(r->first);
}
r->first->second->push_back(item);
sizes[r->first->second.size()].push_back(r->first);

Std sort is declared as this:
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
So you can pass in a comp:
struct comp {
bool operator() (const aVector& lhs, const aVector& rhs) {
return (lhs.size() < rhs.size());
}
} mycomp;
std::sort(theMap, comp)
Note that it is better to pass the comp as an input rather than fix it when you declare the map.
In this case you don't have to declare different maps when you only want to change the comp.

Related

Function on multiple vector

I have a sorting algorithm on a vector, and I want to apply it to several vectors, without knowing how much. The only thing I'm sure is that there will be at least 1 vector (always the same) on which I will perform my algorithm. Other will just follow.
Here's an example :
void sort(std::vector<int>& sortVector, std::vector<double>& follow1, std::vector<char>& follow2, ... ){
for (int i = 1; i<vector.size(); ++i){
if ( vector[i-1] > vector[i] ) { //I know it's not sorting here, it's only for the example
std::swap(vector[i-1], vector[i]);
std::swap(follow1[i-1], follow1[i]);
std::swap(follow2[i-1], follow2[i]);
....
}
}
}
I was thinking about using variadic function, but since it's a recursive function, I was wondering if it won't take too much time to everytime create my va_arg list (I'm working on vector sized 500millions/1billions ...). So does something else exists?
As I'm writing this question, I'm understanding that maybe i'm fooling myself, and there is no other way to achieve what I want and variadic function is maybe not that long. (I really don't know, in fact).
EDIT :
In fact, I'm doing an Octree-sorting of datas in order to be usable in opengl.
Since my datas are not always the same (e.g OBJ files will gives me normals, PTS files will gives me Intensity and Colors, ...), I want to be able to reorder all my vectors (in which are contained my datas) so that they have the same order as the position vectors (The vector that contains the positions of my points, it'll be always here).
But all my vectors will have same length, and I want all my followervector to be reorganised as the first one.
If i have 3 Vectors, if I swap first and third values in my first vector, I want to swap first and thrid values in my 2 others vectors.
But my vectors are not all the same. Some will be std::vector<char>, other std::vector<Vec3>, std::vector<unsigned>, and so on.
With range-v3, you may use zip, something like:
template <typename T, typename ... Ranges>
void sort(std::vector<T>& refVector, Ranges&& ... ranges){
ranges::sort(ranges::view::zip(refVector, std::forward<Ranges>(ranges)...));
}
Demo
Or if you don't want to use ranges to compare (for ties in refVector), you can project to use only refVector:
template <typename T, typename ... Ranges>
void sort(std::vector<T>& refVector, Ranges&& ... ranges){
ranges::sort(ranges::view::zip(refVector, std::forward<Ranges>(ranges)...),
std::less<>{},
[](auto& tup) -> T& { return std::get<0>(tup); });
}
Although, I totally agree with the comment of n.m. I suggest to use a vector of vectors which contain the follow vectors and than do a loop over all follow vectors.
void sort(std::vector<int>& vector, std::vector<std::vector<double>>& followers){
for (int i = 1; i<vector.size(); ++i){
if ( vector[i-1] > vector[i] ) {
std::swap(vector[i-1], vector[i]);
for (auto & follow : followers)
std::swap(follow[i-1], follow[i]);
}
}
}
Nevertheless, as n.m. pointed out, perhaps think about putting all your data you like to sort in a class like structure. Than you can have a vector of your class and apply std::sort, see here.
struct MyStruct
{
int key; //content of your int vector named "vector"
double follow1;
std::string follow2;
// all your inforrmation of the follow vectors go here.
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
};
struct less_than_key
{
inline bool operator() (const MyStruct& struct1, const MyStruct& struct2)
{
return (struct1.key < struct2.key);
}
};
std::vector < MyStruct > vec;
vec.push_back(MyStruct(4, 1.2, "test"));
vec.push_back(MyStruct(3, 2.8, "a"));
vec.push_back(MyStruct(2, 0.0, "is"));
vec.push_back(MyStruct(1, -10.5, "this"));
std::sort(vec.begin(), vec.end(), less_than_key());
The main problem here is that the std::sort algorithm cannot operate on multiple vectors at the same time.
For the purpose of demonstration, let's assume you have a std::vector<int> v1 and a std::vector<char> v2 (of the same size of course) and you want to sort both depending on the values in v1. To solve this, I basically see three possible solutions, all of which generalize to an arbitrary number of vectors:
1) Put all your data into a single vector.
Define a struct, say Data, that keeps an entry of every data vector.
struct Data
{
int d1;
char d2;
// extend here for more vectors
};
Now construct a new std::vector<Data> and fill it from your original vectors:
std::vector<Data> d(v1.size());
for(std::size_t i = 0; i < d.size(); ++i)
{
d[i].d1 = v1[i];
d[i].d2 = v2[i];
// extend here for more vectors
}
Since everything is stored inside a single vector now, you can use std::sort to bring it into order. Since we want it to be sorted based on the first entry (d1), which stores the values of the first vector, we use a custom predicate:
std::sort(d.begin(), d.end(),
[](const Data& l, const Data& r) { return l.d1 < r.d1; });
Afterwards, all data is sorted in d based on the first vector's values. You can now either work on with the combined vector d or you split the data into the original vectors:
std::transform(d.begin(), d.end(), v1.begin(),
[](const Data& e) { return e.d1; });
std::transform(d.begin(), d.end(), v2.begin(),
[](const Data& e) { return e.d2; });
// extend here for more vectors
2) Use the first vector to compute the indices of the sorted range and use these indices to bring all vectors into order:
First, you attach to all elements in your first vector their current position. Then you sort it using std::sort and a predicate that only compares for the value (ignoring the position).
template<typename T>
std::vector<std::size_t> computeSortIndices(const std::vector<T>& v)
{
std::vector<std::pair<T, std::size_t>> d(v.size());
for(std::size_t i = 0; i < v.size(); ++i)
d[i] = std::make_pair(v[i], i);
std::sort(d.begin(), d.end(),
[](const std::pair<T, std::size_t>& l,
const std::pair<T, std::size_t>& r)
{
return l.first < r.first;
});
std::vector<std::size_t> indices(v.size());
std::transform(d.begin(), d.end(), indices.begin(),
[](const std::pair<T, std::size_t>& p) { return p.second; });
return indices;
}
Say in the resulting index vector the entry at position 0 is 8, then this tells you that the vector entries that have to go to the first position in the sorted vectors are those at position 8 in the original ranges.
You then use this information to sort all of your vectors:
template<typename T>
void sortByIndices(std::vector<T>& v,
const std::vector<std::size_t>& indices)
{
assert(v.size() == indices.size());
std::vector<T> result(v.size());
for(std::size_t i = 0; i < indices.size(); ++i)
result[i] = v[indices[i]];
v = std::move(result);
}
Any number of vectors may then be sorted like this:
const auto indices = computeSortIndices(v1);
sortByIndices(v1, indices);
sortByIndices(v2, indices);
// extend here for more vectors
This can be improved a bit by extracting the sorted v1 out of computeSortIndices directly, so that you do not need to sort it again using sortByIndices.
3) Implement your own sort function that is able to operate on multiple vectors. I have sketched an implementation of an in-place merge sort that is able to sort any number of vectors depending on the values in the first one.
The core of the merge sort algorithm is implemented by the multiMergeSortRec function, which takes an arbitrary number (> 0) of vectors of arbitrary types.
The function splits all vectors into first and second half, sorts both halves recursively and merges the the results back together. Search the web for a full explanation of merge sort if you need more details.
template<typename T, typename... Ts>
void multiMergeSortRec(
std::size_t b, std::size_t e,
std::vector<T>& v, std::vector<Ts>&... vs)
{
const std::size_t dist = e - b;
if(dist <= 1)
return;
std::size_t m = b + (dist / static_cast<std::size_t>(2));
// split in half and recursively sort both parts
multiMergeSortRec(b, m, v, vs...);
multiMergeSortRec(m, e, v, vs...);
// merge both sorted parts
while(b < m)
{
if(v[b] <= v[m])
++b;
else
{
++m;
rotateAll(b, m, v, vs...);
if(m == e)
break;
}
}
}
template<typename T, typename... Ts>
void multiMergeSort(std::vector<T>& v, std::vector<Ts>&... vs)
{
// TODO: check that all vectors have same length
if(v.size() < 2)
return ;
multiMergeSortRec<T, Ts...>(0, v.size(), v, vs...);
}
In order to operate in-place, parts of the vectors have to be rotated. This is done by the rotateAll function, which again works on an arbitrary number of vectors by recursively processing the variadic parameter pack.
void rotateAll(std::size_t, std::size_t)
{
}
template<typename T, typename... Ts>
void rotateAll(std::size_t b, std::size_t e,
std::vector<T>& v, std::vector<Ts>&... vs)
{
std::rotate(v.begin() + b, v.begin() + e - 1, v.begin() + e);
rotateAll(b, e, vs...);
}
Note, that the recursive calls of rotateAll are very likely to be inlined by every optimizing compiler, such that the function merely applies std::rotate to all vectors. You can circumvent the need to rotate parts of the vector, if you leave in-place and merge into an additional vector. I like to emphasize that this is neither an optimized nor a fully tested implementation of merge sort. It should serve as a sketch, since you really do not want to use bubble sort whenever you work on large vectors.
Let's quickly compare the above alternatives:
1) is easier to implement, since it relies on an existing (highly optimized and tested) std::sort implementation.
1) needs all data to be copied into the new vector and possibly (depending on your use case) all of it to be copied back.
In 1) multiple places have to be extended if you need to attach additional vectors to be sorted.
The implementation effort for 2) is mediocre (more than 1, but less and easier than 3), but it relies on optimized and tested std::sort.
2) cannot sort in-place (using the indices) and thus has to make a copy of every vector. Maybe there is an in-place alternative, but I cannot think of one right now (at least an easy one).
2) is easy to extend for additional vectors.
For 3) you need to implement sorting yourself, which makes it more difficult to get right.
3) does not need to copy all data. The implementation can be further optimized and can be tweaked for improved performance (out-of-place) or reduced memory consumption (in-place).
3) can work on additional vectors without any change. Just invoke multiMergeSort with one or more additional arguments.
All three work for heterogeneous sets of vectors, in contrast to the std::vector<std::vector<>> approach.
Which of the alternatives performs better in your case, is hard to say and should greatly depend on the number of vectors and their size, so if you really need optimal performance (and/or memory usage) you need to measure.
Find an implementation of the above here.
By far the easiest solution is to create a helper vector std::vector<size_t> initialized with std::iota(helper.begin(), helper.end(), size_t{});.
Next, sort this array,. obviously not by the array index (iota already did that), but by sortvector[i]. IOW, the predicate is [sortvector&](size_t i, size_t j) { sortVector[i] < sortVector[j]; }.
You now have the proper order of array indices. I.e. if helper[0]==17, then it means that the new front of all vectors should be the original 18th element. Usually the easiest way to produce the sorted result is to copy over elements, and then swap the original vector and the copy, repeated for all vectors. But if copying all elements is too expensive, it can be done in-place. (Note that if O(N) element copes are too expensive, a straightforward std::sort tends to perform badly as well as it needs pivots)

How to sort a set of pairs?

How shall I use the qsort function to sort a set of pairs ?
This is my set :
set< pair< int, int> > my_set
This I guess should be my compare function:
int compare (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
Should my qsort look like this?
qsort (my_set, no_of_pairs, sizeof(int), compare);
When I sort them I want to sort by the values of a bi-dimensional array **M;, where
M[my_set.first][my_set.second] = the_value
First, prefer std::sort to qsort with c++ std containers.
Secondly, you cannot sort a std::set a posteriori. std::set is sorted.
You can however specify a custom sorting for the std::set at instanciation using a 2nd template parameter.
Refer to the specs.
What you could do, if you need to sort the data after the fact, is use a std::vector instead. There is an algorithm that will cull the duplicate value.
This proposed solution assumes M is some global variable.
#include <algorithm>
bool less_than(const std::pair<int, int> &some, const std::pair<int, int> &other) {
return M[some.first][some.second] < M[other.first][other.second];
}
std::sort(yourvector.begin(), yourvector.end(), less_than);
If M isn't a global variable, you could do something like that :
struc Compair { // see what I did there ? #sofunny
bool operator() (const std::pair<int, int> &some, const std::pair<int, int> &other) {
return M[some.first][some.second] < M[other.first][other.second];
}
int **M;
}
then in main :
Compair mycomparefunctor;
mycomparefunctor.M = arr; // arr is the original int **
std::sort(yourvector.begin(), yourvector.end(), mycomparefunctor);
EDIT :
If you must use a std::set then you should define the custom ordering when you declare it, like so :
Compair mypredicate;
mypredicate.M = arr; // arr is the original int **
std::set<std::pair<int, int>, mypredicate> myset;
// add stuff to the set. They will be sorted following your predicate.
Be careful though : in a set you cannot add 2 items that compare equal. So if your int ** 2D array has several values that are equal, you won't be able to have several pairs corresponding to indexes of equal value in the set.
You're going about this fairly wrong.
Let's assume that we know the maximum value for each member of the pair. If you don't know this, then you need to figure it out. I'm going to assume that it is 100.
Then all we need to do is iterate over the set, and insert them into the new array. There's no faster way to go about this.
int M[100][100] = {};
for (auto const & pair : my_set)
M[pair.first][pair.second] = the_value;

How can I make an unordered set of pairs of integers in C++?

The following program does not compile an unordered set of pairs of integers, but it does for integers. Can unordered_set and its member functions be used on user-defined types, and how can I define it?
#include <unordered_set>
...
class A{
...
private:
std::unordered_set< std::pair<int, int> > u_edge_;
};
Compiler error:
error: no matching function for call to 'std::unordered_set >::unordered_set()'
There is no standard way of computing a hash on a pair. Add this definition to your file:
struct pair_hash {
inline std::size_t operator()(const std::pair<int,int> & v) const {
return v.first*31+v.second;
}
};
Now you can use it like this:
std::unordered_set< std::pair<int, int>, pair_hash> u_edge_;
This works, because pair<T1,T2> defines equality. For custom classes that do not provide a way to test equality you may need to provide a separate function to test if two instances are equal to each other.
Of course this solution is limited to a pair of two integers. Here is a link to an answer that helps you define a more general way of making hash for multiple objects.
Your code compiles on VS2010 SP1 (VC10), but it fails to compile with GCC g++ 4.7.2.
However, you may want to consider boost::hash from Boost.Functional to hash a std::pair (with this addition, your code compiles also with g++).
#include <unordered_set>
#include <boost/functional/hash.hpp>
class A
{
private:
std::unordered_set<
std::pair<int, int>,
boost::hash< std::pair<int, int> >
> u_edge_;
};
The problem is that std::unordered_set is using std::hash template to compute hashes for its entries and there is no std::hash specialization for pairs. So you will have to do two things:
Decide what hash function you want to use.
Specialize std::hash for your key type (std::pair<int, int>) using that function.
Here is a simple example:
#include <unordered_set>
namespace std {
template <> struct hash<std::pair<int, int>> {
inline size_t operator()(const std::pair<int, int> &v) const {
std::hash<int> int_hasher;
return int_hasher(v.first) ^ int_hasher(v.second);
}
};
}
int main()
{
std::unordered_set< std::pair<int, int> > edge;
}
As already mentioned in most of the other answers on this question, you need to provide a hash function for std::pair<int, int>. However, since C++11, you can also use a lambda expression instead of defining a hash function. The following code takes the solution given by Sergey as basis:
auto hash = [](const std::pair<int, int>& p){ return p.first * 31 + p.second; };
std::unordered_set<std::pair<int, int>, decltype(hash)> u_edge_(8, hash);
Code on Ideone
I'd like repeat Sergey's disclaimer: This solution is limited to a pair of two integers. This answer provides the idea for a more general solution.
OK here is a simple solution with guaranteed non collisions. Simply reduce your problem to an existing solution i.e. convert your pair of int to string like so:
auto stringify = [](const pair<int, int>& p, string sep = "-")-> string{
return to_string(p.first) + sep + to_string(p.second);
}
unordered_set<string> myset;
myset.insert(stringify(make_pair(1, 2)));
myset.insert(stringify(make_pair(3, 4)));
myset.insert(stringify(make_pair(5, 6)));
Enjoy!
You need to provide a specialization for std::hash<> that works with std::pair<int, int>. Here is a very simple example of how you could define the specialization:
#include <utility>
#include <unordered_set>
namespace std
{
template<>
struct hash<std::pair<int, int>>
{
size_t operator () (std::pair<int, int> const& p)
{
// A bad example of computing the hash,
// rather replace with something more clever
return (std::hash<int>()(p.first) + std::hash<int>()(p.second));
}
};
}
class A
{
private:
// This won't give you problems anymore
std::unordered_set< std::pair<int, int> > u_edge_;
};
The other answers here all suggest building a hash function that somehow combines your two integers.
This will work, but produces non-unique hashes. Though this is fine for your use of unordered_set, for some applications it may be unacceptable. In your case, if you happen to choose a bad hash function, it may lead to many unnecessary collisions.
But you can produce unique hashes!
int is usually 4 bytes. You could make this explicit by using int32_t.
The hash's datatype is std::size_t. On most machines, this is 8 bytes. You can check this upon compilation.
Since a pair consists of two int32_t types, you can put both numbers into an std::size_t to make a unique hash.
That looks like this (I can't recall offhandedly how to force the compiler to treat a signed value as though it were unsigned for bit-manipulation, so I've written the following for uint32_t.):
#include <cassert>
#include <cstdint>
#include <unordered_set>
#include <utility>
struct IntPairHash {
std::size_t operator()(const std::pair<uint32_t, uint32_t> &p) const {
assert(sizeof(std::size_t)>=8); //Ensure that std::size_t, the type of the hash, is large enough
//Shift first integer over to make room for the second integer. The two are
//then packed side by side.
return (((uint64_t)p.first)<<32) | ((uint64_t)p.second);
}
};
int main(){
std::unordered_set< std::pair<uint32_t, uint32_t>, IntPairHash> uset;
uset.emplace(10,20);
uset.emplace(20,30);
uset.emplace(10,20);
assert(uset.size()==2);
}
You are missing a hash function for std::pair<int, int>>. For example,
struct bad_hash
{
std::size_t operator()(const std::pair<int,int>& p) const
{
return 42;
}
};
....
std::unordered_set< std::pair<int, int>, bad_hash> u_edge_;
You can also specialize std::hash<T> for std::hash<std::pair<int,int>>, in which case you can omit the second template parameter.
To make a unordered_set of pairs, you can either create a custom hash function or you can make an unordered_set of strings.
Create custom hash function: Creating the custom hash depends on the data. So there is no one size fits all hash function. A good hash function must have fewer collisions, so you need to consider the collision count while making the hash function.
Using Strings: Using string is very simple and takes less time. It also guarantees few or no collisions. Instead of using an unordered_set<pair<int, int>> we use an unordered_set. We can represent the pair by separating the numbers with a separator (character or string). The example given below shows how you can insert pair of integers with the separator (";").
auto StringPair = [](const pair<int, int>& x){return to_string(x.first) + ";" + to_string(x.second);};
unordered_set Set;
vector<pair<int, int>> Nums = {{1,2}, {2, 3}, {4, 5}, {1,2}};
for(auto & pair: Nums)
{
Set.insert(StringPair(pair));
}
Just to add my 2 cents here, it's weird that to use unordered_set you need to specify an external hash function. Encapsulation principle would prefer that inside your class you would have an 'hash()' function that returns the hash, and the unordered_set would call that. You should have an Hashable interface and your class, in this case std::pair, would implement that interface.
I think this is the approach followed by languages like Java. Unfortunately C++ doesn't follow this logic. The closest you can get to mimic that is:
derive a class from std::pair (this allows you to have more readable code anyway)
pass the hash function to the unordered_set template
Code Sample
class Point : public pair<int, int> {
public:
int &x = this->first; // allows to use mypoint.x for better readability
int &y = this->second; // allows to use mypoint.y for better readability
Point() {};
Point(int first, int second) : pair{first, second}{};
class Hash {
public:
auto operator()(const Point &p) const -> size_t {
return ((size_t)p.first) << 32 | ((size_t)p.second);
}
};
};
int main()
{
unordered_set< Point, Point::Hash > us;
Point mypoint(1000000000,1);
size_t res = Point::Hash()(mypoint);
cout<<"Hello World " << res << " " << mypoint.x;
return 0;
}
The simple hash function used works if size_t is 64bit and int is 32bit, in this case this hash function guarantees no collisions and it's ideal.

algorithm to remove elements in the intersection of two sets

I have a Visual Studio 2008 C++03 application where I have two standard containers. I would like to remove from one container all of the items that are present in the other container (the intersection of the sets).
something like this:
std::vector< int > items = /* 1, 2, 3, 4, 5, 6, 7 */;
std::set< int > items_to_remove = /* 2, 4, 5*/;
std::some_algorithm( items.begin, items.end(), items_to_remove.begin(), items_to_remove.end() );
assert( items == /* 1, 3, 6, 7 */ )
Is there an existing algorithm or pattern that will do this or do I need to roll my own?
Thanks
Try with:
items.erase(
std::remove_if(
items.begin(), items.end()
, std::bind1st(
std::mem_fun( &std::set< int >::count )
, items_to_remove
)
)
, items.end()
);
std::remove(_if) doesn't actually remove anything, since it works with iterators and not containers. What it does is reorder the elements to be removed at the end of the range, and returns an iterator to the new end of the container. You then call erase to actually remove from the container all of the elements past the new end.
Update: If I recall correctly, binding to a member function of a component of the standard library is not standard C++, as implementations are allowed to add default parameters to the function. You'd be safer by creating your own function or function-object predicate that checks whether the element is contained in the set of items to remove.
Personally, I prefer to create small helpers for this (that I reuse heavily).
template <typename Container>
class InPredicate {
public:
InPredicate(Container const& c): _c(c) {}
template <typename U>
bool operator()(U const& u) {
return std::find(_c.begin(), _c.end(), u) != _c.end();
}
private:
Container const& _c;
};
// Typical builder for automatic type deduction
template <typename Container>
InPredicate<Container> in(Container const& c) {
return InPredicate<Container>(c);
}
This also helps to have a true erase_if algorithm
template <typename Container, typename Predicate>
void erase_if(Container& c, Predicate p) {
c.erase(std::remove_if(c.begin(), c.end(), p), c.end());
}
And then:
erase_if(items, in(items_to_remove));
which is pretty readable :)
One more solution:
There is standard provided algorithm set_difference which can be used for this.
But it requires extra container to hold the result. I personally prefer to do it in-place.
std::vector< int > items;
//say items = [1,2,3,4,5,6,7,8,9]
std::set<int>items_to_remove;
//say items_to_remove = <2,4,5>
std::vector<int>result(items.size()); //as this algorithm uses output
//iterator not inserter iterator for result.
std::vector<int>::iterator new_end = std::set_difference(items.begin(),
items.end(),items_to_remove.begin(),items_to_remove.end(),result.begin());
result.erase(new_end,result.end()); // to erase unwanted elements at the
// end.
You can use std::erase in combination with std::remove for this. There is a C++ idiom called the Erase - Remove idiom, which is going to help you accomplish this.
Assuming you have two sets, A and B, and you want to remove from B, the intersection, I, of (A,B) such that I = A^B, your final results will be:
A (left intact)
B' = B-I
Full theory:
http://math.comsci.us/sets/difference.html
This is quite simple.
Create and populate A and B
Create a third intermediate vector, I
Copy the contents of B into I
For each element a_j of A, which contains j elements, search I for the element a_j; If the element is found in I, remove it
Finally, the code to remove an individual element can be found here:
How do I remove an item from a stl vector with a certain value?
And the code to search for an item is here:
How to find if an item is present in a std::vector?
Good luck!
Here's a more "hands-on" in-place method that doesn't require fancy functions nor do the vectors need to be sorted:
#include <vector>
template <class TYPE>
void remove_intersection(std::vector<TYPE> &items, const std::vector<TYPE> &items_to_remove)
{
for (int i = 0; i < (int)items_to_remove.size(); i++) {
for (int j = 0; j < (int)items.size(); j++) {
if (items_to_remove[i] == items[j]) {
items.erase(items.begin() + j);
j--;//Roll back the iterator to prevent skipping over
}
}
}
}
If you know that the multiplicity in each set is 1 (not a multiset), then you can actually replace the j--; line with a break; for better performance.

Search in vector<std::pair<int, vector<int> > >

I would like to search within a vector<std::pair<int, vector<int> > >. This won't work due to the vector parameters:
std::vector<std::pair<int, std::vector<int> > > myVec;
iterator = find(myVec.begin(), myVec.end(), i);
Search would be on the first std::pair template parameter (int), in order to get the vector associated with it.
std::vector<std::pair<int, std::vector<int> > > myVec;
This requires C++0x for the lambda expression:
typedef std::pair<int, std::vector<int>> pair_type
std::find_if(myVec.begin(), myVec.end(), [i](pair_type const& pair)
{ return pair.first == i; });
If you're not using C++0x then either roll out your own loop or use something like Boost.Phoenix/Boost.Lambda.
Or, for both cases, why not use std::map?
You could make do with the following (pretty ugly) functoid:
struct FindFirst {
FindFirst(int i) : toFind(i) { }
int toFind;
bool operator()
( const std::pair<int, std::vector<int> > &p ) {
return p.first==toFind;
}
};
using it like this ( I couldn't get bind2nd to work - that's why I used the c'tor ):
int valueToFind = 4;
std::find_if(myVec.begin(), myVec.end(), FindFirst(valueToFind));
I think what you would like is a map:
std::map< int, vector< int > > foo;
You can then add elements, search by key etc:
int key = 4; //This will be the key
vector<int> value(5, 4); //Fill some values (5 4's in this case) into the vector
foo[key]=value; //Adds the pair to the map. Alternatively;
foo.insert( make_pair(key, value) ); //Does the same thing (in this context)
Looking at the way you've done things though, you might be wanting a std::multimap (which allows multiple values to have the same key) Class docs here
You're trying to map an int to a vector of int.
So try map<int, vector<int> >.
The second template parameter of a vector is the allocator - your compiler can probably puzzle out what you wanted to say, the declaration is wrong anyway. What you probably want is some sort of map type, like iammilind suggested.