Here is what I do and would like to if someone has a cleaner solution:
vector<string> vec;
multimap<stirng, int> myMap
// populate myMap
multimap<string, int >::iterator iter = myMap.begin();
while(iter != myMap.end())
{
vec.push_back(iter->first)
}
Whats wrong with
std::copy(myMap.begin(),myMap.end(),std::back_inserter(vec)); ?
You could do a reserve on vec first to improve performance.
/Peter
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>
#include <iostream>
template<typename C, typename M>
class key_inserter :
public std::iterator<std::output_iterator_tag,void,void,void,void> {
private:
C & d_coll;
public:
key_inserter(C & c) : d_coll(c) {}
key_inserter & operator*() { return *this; }
key_inserter & operator++() { return *this; }
key_inserter & operator++(int) { return *this; }
key_inserter &
operator=(typename M::value_type const & p) {
d_coll.push_back(p.first);
return *this;
}
};
template<typename C, typename M>
key_inserter<C,M> make_key_inserter(C & c, M & m) {
return key_inserter<C,M>(c);
}
int main() {
std::vector<int> v;
std::map<int,int> m;
m[0];m[1];m[2];m[6];
std::copy(m.begin(),
m.end(),
make_key_inserter(v,m));
std::copy(v.begin(),
v.end(),
std::ostream_iterator<int>(std::cout,"\n"));
return 0;
}
--
OU
Remember 18th of June 2008, Democracy died that afternoon.
http://frapedia.se/wiki/Information_in_English
I did not see that. Don't ask the question in the title (but read the
title anyway!).
In that case, I'd recommend having a look at Boosts iterator adaptors
which should do the job. But I admit that I haven't looked at that
part of Boost for a while (and never used it).
/Peter
I think this works:
struct MyFunctor
{
typedef std::multimap <std::string, int> StringIntMultiMap;
std::string operator () (StringIntMultiMap::value_type const & v)
const
{
return v.first;
}
};
std::transform (myMap.begin (), myMap.end (), back_inserter (vec),
MyFunctor ());
HTH
You'll need a functor to extract that string from multimap's
value_type and std::transform can process the elements.
#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <map>
#include <iterator>
template< typename P >
struct extract_first
{
const typename P::first_type&
operator()(const P& p) const
{
return p.first;
}
};
int main()
{
std::vector< std::string > vec;
std::multimap< std::string, int > mm;
// populate mm
typedef std::multimap< std::string, int >::value_type VType;
std::transform( mm.begin(),
mm.end(),
std::back_inserter(vec),
extract_first< VType >() );
}
Exactly... that's not going to work, I don't need the value_key, which
is pair<string, int>
Thanks
Given that the while loop solution only requires 2 lines of code, I
think it's the easier solution... ;)
You could use std::transform with std::back_inserter to load vector
and a functor to extract the std::string from multimap's value_type.
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
Alternatively, one can put the template inside:
// same headers
struct extract_first {
template< typename P >
typename P::first_type const &
operator()(const P& p) const {
return p.first;
}
};
int main() {
std::vector< std::string > vec;
std::multimap< std::string, int > mm;
// populate mm
std::transform( mm.begin(),
mm.end(),
std::back_inserter(vec),
extract_first() );
}
This makes extract_first oblivious to the type actually being used. I am not
sure, which is better. Any thoughts?
Best
Kai-Uwe Bux
That's exactly my point. Guys, do you see how this solution is
verbose, cluttered, and not particularly expressive over my
traditional solution? Meyers allegedly encourages to use transforms,
copy and other algorithms in the STL library. And I am confident that
for this problem, he would still pick a stl-like solution. However,
using transform, in this case, doesn't telegraph your intent -- that
you want to copy keys to from a multimap into a vector -whereas a loop
with fairly descriptive variable names would.
I bring this example, because I have stumbled upon a huge amount of
code, where STL is [ab]used rather excessively, not only making the
code hard to read, maintain, but also fix bugs in it. However, this
particular example is coming from my 'fix' where I considered using
hardcore stl or a trivial loop, I chose the latter.
Thoughts?
I like your solution, but the "canonical" solution, I think, is the
former (looking at SGI's select1st functor). That being said, I can't
think of a case where your solution would be any worse.
Well, the "extract_first" functor is reusable. You only have to write
it down once. Your problem is solved with one function call. Also, I
like the fact that Kai-Uwe's solution is NOT cluttered with names of
types (iterator, value_type, ...). In the upcoming C++ version I would
probably prefer the new for-range construct along with type inference
to avoid this:
#include <for>
:
for (auto & p : mymultimap) myvector.push(p.first);
:
This will also avoid the creation of a temporary copy of pair.first
because operator() in extract_first returns a copy. Of course you
could define this function to return a const reference and I think
this will be ok in this situation because the pair reference is NOT a
temporary. But it may lead to danling references in other cases. So,
coding your own loop is more efficient.
Cheers,
SG
> Obnoxious User wrote:
[snip]
>
> Given that the while loop solution only requires 2 lines of code, I
> think it's the easier solution... ;)
On the other hand, if this action is required in multiple
places, then I would prefer some sort of abstraction instead
of a simple while loop.
> // populate myMap
Do you really want multiple entries in the vector when there are
multiple entries for a single key in the map? If so, something
like the following should work:
template< typename Pair >
struct First
{
typedef Pair argument_type ;
typedef typename Pair::first_type
result_type ;
typename Pair::first_type
operator()( Pair const& obj ) const
{
return obj.first ;
}
} ;
and then:
typedef First< Map::value_type >
Mapper ;
typedef boost::transform_iterator< Mapper, Map::const_iterator >
InitIter ;
std::vector< std::string >
k( InitIter( m.begin(), Mapper() ),
InitIter( m.end(), Mapper() ) ) ;
If you only want each unique key to appear once, then you should
be able to use a boost::filter_iterator on the
transform_iterator.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> Given that the while loop solution only requires 2 lines of
> code, I think it's the easier solution... ;)
But it isn't kool, or in:-).
A lot depends on context. If you often have code which can use
the standard algorithms, provided you can map to only the key or
the mapped type, then it's worth writing functional objects
which do this mapping, and using boost::transform_iterator as
arguments to the constructor. For a one of use, on the other
hand, it's really a question of why be simple, when you can be
complicated. Unless, of course, your goal is mainly to show
off.
> That's exactly my point. Guys, do you see how this solution
> is verbose, cluttered, and not particularly expressive over my
> traditional solution? Meyers allegedly encourages to use
> transforms, copy and other algorithms in the STL library. And
> I am confident that for this problem, he would still pick a
> stl-like solution. However, using transform, in this case,
> doesn't telegraph your intent
It doesn't. You're transforming the values of a map into
strings (or whatever).
This merits a half a :-). I actually agree with you. But
mainly because despite the contortions of the standard library;
a map conceptually isn't a "container" of objects, but has keys
and values. And you don't want to transform the keys, just copy
them. If you think of a map as a container of key-value pairs,
which is how the standard library views it, then you are
transforming a key-value pair into a key.
You can also think of an std::map as relation (in the relational
algebra sense). In this model transform is equivalent to the
projection operation. Boost.Multimap makes the model more explicit,
but it also works well for standard associative containers.
--
gpd
James, you're essentially supporting the claim not only in regard
to my example, but STL in general. Even though STL solves a lot of
computational problems, it does in fact have a tendency to
introduce maintenance and readability nightmare.
Boost, ah, we don't use it in our shop.
Is there a list of companies who use Boost ?
Thanks