copy from keys from multimap into the vector

P

puzzlecracker

I am using while loop for that but I am sure you can do it quicker and
more syntactically clear with copy function.

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)
}
 
P

peter koch

I am using while loop for that but I am sure you can do it quicker and
more syntactically clear with copy function.

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
 
A

AnonMail2005

I am using while loop for that but I am sure you can do it quicker and
Whats wrong with
std::copy(myMap.begin(),myMap.end(),std::back_inserter(vec)); ?
A map's element contains both the key and the value so this is not
correct.
The OP just wants the key.
 
P

peter koch

A map's element contains both the key and the value so this is not
correct.
The OP just wants the key.

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
 
A

AnonMail2005

I am using while loop for that but I am sure you can do it quicker and
more syntactically clear with copy function.

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)
    }

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
 
S

Salt_Peter

I am using while loop for that but I am sure you can do it quicker and
more syntactically clear with copy function.

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)
    }

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 >() );
}
 
P

puzzlecracker

A map's element contains both the key and the value so this is not
correct.
The OP just wants the key.

Exactly... that's not going to work, I don't need the value_key, which
is pair<string, int>

Thanks
 
J

Juha Nieminen

Obnoxious said:
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>
#include <iostream>

template<typename C, typename M>
class key_inserter :
public std::iterator<std::eek:utput_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::eek:stream_iterator<int>(std::cout,"\n"));
return 0;
}

Given that the while loop solution only requires 2 lines of code, I
think it's the easier solution... ;)
 
S

Salt_Peter

I am using while loop for that but I am sure you can do it quicker and
more syntactically clear with copy function.

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)
    }

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>
#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 >() );
}
 
K

Kai-Uwe Bux

Salt_Peter said:
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>
#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 >() );
}

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
 
P

puzzlecracker

Given that the while loop solution only requires 2 lines of code, I
think it's the easier solution... ;)

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?
 
T

Triple-DES

Salt_Peter wrote:






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?

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.
 
S

SG

That's exactly my point. Guys, do you see how this solution is
verbose, cluttered, and not particularly expressive over my
traditional solution?

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
 
J

James Kanze

I am using while loop for that but I am sure you can do it
quicker and more syntactically clear with copy function.
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)
}

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.
 
J

James Kanze

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.
 
J

James Kanze

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.
 
G

gpderetta

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.
 
P

puzzlecracker

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.

--
James Kanze (GABI Software)             email:[email protected]
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

James, you're essentially supporting my asserting not only in regard
to my example, but STL in general. Even though STL solves a lot of
computational problems, but it does in fact has 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
 
P

puzzlecracker

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.

--
James Kanze (GABI Software)             email:[email protected]
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

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 has 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
 
P

puzzlecracker

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.

--
James Kanze (GABI Software)             email:[email protected]
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

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top