STL map to STL vector

Discussion in 'C++' started by Luca Risolia, Jan 13, 2014.

  1. Luca Risolia

    Luca Risolia Guest

    Mike Copeland wrote:

    > Is it possible to simply (single statement) move the data from one
    > container type (the TeamMap, below) to a different type of container
    > (the TeamVector, below)?


    std::for_each(std::make_move_iterator(std::begin(TeamMap)),
    std::make_move_iterator(std::end(TeamMap)),
    [](decltype(TeamMap)::value_type&& v) {
    TeamVector.push_back(std::move(v.second));
    });
     
    Luca Risolia, Jan 13, 2014
    #1
    1. Advertising

  2. Is it possible to simply (single statement) move the data from one
    container type (the TeamMap, below) to a different type of container
    (the TeamVector, below)? My data resides in the map object, but since I
    have to occasionally display the data in different orders (e.g.
    teamName, teamTypeCode), I must copy the data to a vector and sort it
    before producing my listings.
    I know that I can copy the individual objects from the map to the
    vector one-at-a-time, but I'm hoping that there's a technique that will
    do it simply and quickly. Any thoughts? TIA


    typedef map<char, int> ShirtStats;
    struct TeamData
    {
    bool isAdded; // Added to container data
    bool isValidTeam; // really is a team
    char teamTypeCode; // Team type Code
    int teamMembers1; // Count of Team Members-1
    int teamMembers2; // Count of Team Members-2
    int genderCounts[NMAXEVT][2]; // counts of Gender by Event
    int shirtTotalMatrix[5][8];
    string teamCode; // Team's Code (strTId)
    string teamName; // Team's Name
    ShirtStats shirtStats;
    } extern teamWork;
    typedef map<string, TeamData> TeamMap;
    TeamMap::iterator tIter;
    ShirtStats::iterator ssIter;
    TeamMap teamMap;
    typedef vector<TeamData> TeamVector;
    typedef TeamVector::iterator TeamIter;
    TeamVector teamVect;
    TeamIter tvIter;

    ---
    This email is free from viruses and malware because avast! Antivirus protection is active.
    http://www.avast.com
     
    Mike Copeland, Jan 14, 2014
    #2
    1. Advertising

  3. Luca Risolia

    Ian Collins Guest

    Mike Copeland wrote:
    > Is it possible to simply (single statement) move the data from one
    > container type (the TeamMap, below) to a different type of container
    > (the TeamVector, below)? My data resides in the map object, but since I
    > have to occasionally display the data in different orders (e.g.
    > teamName, teamTypeCode), I must copy the data to a vector and sort it
    > before producing my listings.
    > I know that I can copy the individual objects from the map to the
    > vector one-at-a-time, but I'm hoping that there's a technique that will
    > do it simply and quickly. Any thoughts? TIA


    Construct the vector using the map's beginning and end:

    TeamVector t( teamMap.begin(), teamMap.end() );

    --
    Ian Collins
     
    Ian Collins, Jan 14, 2014
    #3
  4. Luca Risolia

    Guest

    On Monday, January 13, 2014 6:06:47 PM UTC-6, Mike Copeland wrote:
    > Is it possible to simply (single statement) move the data from one
    > container type (the TeamMap, below) to a different type of container
    >
    > (the TeamVector, below)? My data resides in the map object, but since I
    > have to occasionally display the data in different orders (e.g.
    > teamName, teamTypeCode), I must copy the data to a vector and sort it
    > before producing my listings.
    > I know that I can copy the individual objects from the map to the
    > vector one-at-a-time, but I'm hoping that there's a technique that will
    > do it simply and quickly. Any thoughts? TIA
    >


    How about

    http://www.boost.org/doc/libs/1_55_0/libs/multi_index/doc/index.html


    That would help you avoid the copying.

    Brian
    Ebenezer Enterprises - In G-d we trust.
    http://webEbenezer.net
     
    , Jan 14, 2014
    #4
  5. Luca Risolia

    Ike Naar Guest

    On 2014-01-14, Ian Collins <> wrote:
    > Mike Copeland wrote:
    >> Is it possible to simply (single statement) move the data from one
    >> container type (the TeamMap, below) to a different type of container
    >> (the TeamVector, below)? My data resides in the map object, but since I
    >> have to occasionally display the data in different orders (e.g.
    >> teamName, teamTypeCode), I must copy the data to a vector and sort it
    >> before producing my listings.
    >> I know that I can copy the individual objects from the map to the
    >> vector one-at-a-time, but I'm hoping that there's a technique that will
    >> do it simply and quickly. Any thoughts? TIA

    >
    > Construct the vector using the map's beginning and end:
    >
    > TeamVector t( teamMap.begin(), teamMap.end() );


    That won't work because the value type of the map is not the same as the
    value type of the vector.
     
    Ike Naar, Jan 14, 2014
    #5
  6. Luca Risolia

    Ike Naar Guest

    On 2014-01-13, Luca Risolia <> wrote:
    > Mike Copeland wrote:
    >
    >> Is it possible to simply (single statement) move the data from one
    >> container type (the TeamMap, below) to a different type of container
    >> (the TeamVector, below)?

    >
    > std::for_each(std::make_move_iterator(std::begin(TeamMap)),
    > std::make_move_iterator(std::end(TeamMap)),
    > [](decltype(TeamMap)::value_type&& v) {
    > TeamVector.push_back(std::move(v.second));
    > });


    From Mike's description (snipped) it looks like he wants to copy the
    data, not move it.
     
    Ike Naar, Jan 14, 2014
    #6
  7. Luca Risolia

    Ian Collins Guest

    Ike Naar wrote:
    > On 2014-01-14, Ian Collins <> wrote:
    >> Mike Copeland wrote:
    >>> Is it possible to simply (single statement) move the data from one
    >>> container type (the TeamMap, below) to a different type of container
    >>> (the TeamVector, below)? My data resides in the map object, but since I
    >>> have to occasionally display the data in different orders (e.g.
    >>> teamName, teamTypeCode), I must copy the data to a vector and sort it
    >>> before producing my listings.
    >>> I know that I can copy the individual objects from the map to the
    >>> vector one-at-a-time, but I'm hoping that there's a technique that will
    >>> do it simply and quickly. Any thoughts? TIA

    >>
    >> Construct the vector using the map's beginning and end:
    >>
    >> TeamVector t( teamMap.begin(), teamMap.end() );

    >
    > That won't work because the value type of the map is not the same as the
    > value type of the vector.


    Whoops, you're right. I was thinking of std::set, not map.

    --
    Ian Collins
     
    Ian Collins, Jan 14, 2014
    #7
  8. On 14.01.2014 08:30, Ian Collins wrote:
    > Ike Naar wrote:
    >> On 2014-01-14, Ian Collins <> wrote:
    >>> Mike Copeland wrote:
    >>>> Is it possible to simply (single statement) move the data from one
    >>>> container type (the TeamMap, below) to a different type of container
    >>>> (the TeamVector, below)? My data resides in the map object, but
    >>>> since I
    >>>> have to occasionally display the data in different orders (e.g.
    >>>> teamName, teamTypeCode), I must copy the data to a vector and sort it
    >>>> before producing my listings.
    >>>> I know that I can copy the individual objects from the map to the
    >>>> vector one-at-a-time, but I'm hoping that there's a technique that will
    >>>> do it simply and quickly. Any thoughts? TIA
    >>>
    >>> Construct the vector using the map's beginning and end:
    >>>
    >>> TeamVector t( teamMap.begin(), teamMap.end() );

    >>
    >> That won't work because the value type of the map is not the same as the
    >> value type of the vector.

    >
    > Whoops, you're right. I was thinking of std::set, not map.
    >


    The following little class comes in handy then:


    Code:
    template< class Iter, class Referent, class Remap_func >
    struct Remap_iter
    : Iter
    {
    typedef Iter Base;
    
    Referent& operator* ()
    { return Remap_func()( Base::operator*() ); }
    
    Referent const& operator* () const
    { return Remap_func()( Base::operator*() ); }
    
    Remap_iter( Iter const& it )
    : Base( it )
    {}
    };
    [code]
    
    
    It doesn't cover all the cases but one can just add to it. Good enough
    for Mike's code with Visual C++. That is,
    
    
    [code]
    struct Map_to_vec
    {
    TeamData& operator()( TeamMap::value_type& v )
    { return v.second; }
    };
    
    int main()
    {
    typedef Remap_iter< TeamMap::iterator, TeamData, Map_to_vec > Vec_iter;
    
    TeamMap         m;
    TeamVector      v( Vec_iter( m.begin() ), Vec_iter( m.end() ) );
    }
    

    compiles nicely.

    Disclaimer: haven't tested it with any data!


    Cheers & hth.,

    - Alf
     
    Alf P. Steinbach, Jan 14, 2014
    #8
  9. On 14.01.2014 10:49, Juha Nieminen wrote:
    > Alf P. Steinbach <> wrote:
    >> The following little class comes in handy then:

    >
    > Or instead you could do the sensible thing and use a 1-liner:
    >
    > for(auto& element: theMap) theVector.push_back(element.second);


    I'm not sure it's always so sensible as a /general/ solution, which I
    somewhat unthinkingly aimed at.

    In particular, if you want to declare `theVector` as `const`, which is
    usually a good idea since one can then be sure at a glance that it won't
    change, then the above approach needs a lambda or named function:

    vector<TeamData> theVector( [&]() -> vector<TeamData>
    {
    vector<TeamData> result;
    for(auto& element: m) theVector.push_back(element.second);
    return result;
    }() );

    Like, ouch. I think the "iterator conversion" approach stands a much
    better chance of reducing that to something more simple &
    straightforward, something without case-specific code. Perhaps even
    something readable...

    However, I agree that the loop is probably the best advice to Mike, the OP.

    Dang, I didn't think of that.


    Cheers,

    - Alf
     
    Alf P. Steinbach, Jan 14, 2014
    #9
  10. On 2014-01-13 15:39, Luca Risolia wrote:
    > Mike Copeland wrote:
    >
    >> Is it possible to simply (single statement) move the data from one
    >> container type (the TeamMap, below) to a different type of container
    >> (the TeamVector, below)?

    >
    > std::for_each(std::make_move_iterator(std::begin(TeamMap)),
    > std::make_move_iterator(std::end(TeamMap)),
    > [](decltype(TeamMap)::value_type&& v) {
    > TeamVector.push_back(std::move(v.second));
    > });


    (Assuming you want to move the contents)

    Given the following declarations:
    > struct TeamData;
    > typedef std::map<std::string, TeamData> TeamMap; TeamMap teamMap;
    > typedef std::vector<TeamData> TeamVector; TeamVector teamVect;


    It should read like this:

    std::for_each(std::make_move_iterator(std::begin(teamMap)),
    std::make_move_iterator(std::end(teamMap)),
    [&](decltype(teamMap)::value_type&& v) {
    teamVect.push_back(std::move(v.second));
    });

    By the way, I think it can be made simpler like this:

    std::for_each(std::begin(teamMap),
    std::end(teamMap),
    [&](decltype(teamMap)::value_type& v) {
    teamVect.push_back(std::move(v.second));
    });

    A function that takes an lvalue parameter and moves things out of it
    is dangerous in general, but this is a lambda function used specifically
    for moving the contents out of an existing container, so it is okay.
    And whether you take an lvalue parameter or an rvalue parameter,
    it becomes an lvalue inside the function and you need std::move anyway.

    --
    Seungbeom Kim
     
    Seungbeom Kim, Jan 14, 2014
    #10
  11. Luca Risolia

    Guest

    On Tuesday, January 14, 2014 3:14:09 PM UTC-6, Mr Flibble wrote:

    >
    > Actually the benefit of doing 'reserve' diminishes as the number of
    > elements increases.



    Maps may be the worst standard container.
    I also avoid std::list.


    Brian
    Ebenezer Enterprises - So far G-d has helped us.
    http://webEbenezer.net
     
    , Jan 14, 2014
    #11
  12. Luca Risolia

    Jorgen Grahn Guest

    On Tue, 2014-01-14, wrote:
    > On Tuesday, January 14, 2014 3:14:09 PM UTC-6, Mr Flibble wrote:
    >
    >>
    >> Actually the benefit of doing 'reserve' diminishes as the number of
    >> elements increases.

    >
    > Maps may be the worst standard container.


    Why? I find it invaluable -- it gives you the type->type mapping most
    modern languages have. (Of course, unordered_map does most of the
    same things, and for the few cases where it matters, slightly faster.)

    /Jorgen

    --
    // Jorgen Grahn <grahn@ Oo o. . .
    \X/ snipabacken.se> O o .
     
    Jorgen Grahn, Jan 14, 2014
    #12
  13. Luca Risolia

    Guest

    On Tuesday, January 14, 2014 4:36:46 PM UTC-6, Jorgen Grahn wrote:
    > On Tue, 2014-01-14, wrote:


    > > Maps may be the worst standard container.

    >
    > Why? I find it invaluable -- it gives you the type->type mapping most
    > modern languages have. (Of course, unordered_map does most of the
    > same things, and for the few cases where it matters, slightly faster.)
    >


    I think the pair based interface is flawed and there should
    instead be a container like Boost.intrusive.rbtree in the
    standard. It wouldn't have to be intrusive, but it
    wouldn't be pair based. Then you're able to work with one
    type rather than two types. No more "first' and "second".
    Multi_index doesn't use pair in its interface either.

    I don't know if what Leigh wrote is correct, but if it is
    that would be another strike against maps.

    Maps keep track of the number of elements in them. The
    boost intrusive library gives you the option to not
    have to pay for keeping track of the elements like that.

    I think unordered_map is a lame name.

    Brian
    Ebenezer Enterprises - Heavenly code.
    http://webEbenezer.net
     
    , Jan 15, 2014
    #13
  14. Luca Risolia

    Guest

    On Tuesday, January 14, 2014 10:49:02 AM UTC+1, Juha Nieminen wrote:
    > Alf P. Steinbach <> wrote:
    >
    > > The following little class comes in handy then:

    >
    >
    >
    > Or instead you could do the sensible thing and use a 1-liner:
    >
    >
    >
    > for(auto& element: theMap) theVector.push_back(element.second);
    >
    >
    >
    > --- news://freenews.netfront.net/ - complaints: ---



    std::transform(team_map.begin(), team_map.end(), std::back_inserter(team_vec),
    [](decltype(team_map)::value_type e) { return e.second; });

    One liner is indeed much clearer :)
     
    , Jan 15, 2014
    #14
  15. Luca Risolia

    Öö Tiib Guest

    On Wednesday, 15 January 2014 05:38:02 UTC+2, wrote:
    > On Tuesday, January 14, 2014 4:36:46 PM UTC-6, Jorgen Grahn wrote:
    > > On Tue, 2014-01-14, wrote:

    >
    > > > Maps may be the worst standard container.

    > >
    > > Why? I find it invaluable -- it gives you the type->type mapping most
    > > modern languages have. (Of course, unordered_map does most of the
    > > same things, and for the few cases where it matters, slightly faster.)
    > >

    >
    > I think the pair based interface is flawed and there should
    > instead be a container like Boost.intrusive.rbtree in the
    > standard.


    That tree is not map. Map consists of relations of value
    of some type to other value of (possibly some other) type.
    Such relations or "mappings" are the point of map. You
    can use tree of mappings as map but then you need to
    describe what is mapping.

    > It wouldn't have to be intrusive, but it
    > wouldn't be pair based. Then you're able to work with one
    > type rather than two types. No more "first' and "second".
    > Multi_index doesn't use pair in its interface either.


    Pair is a way to represent a mapping. There may be
    endless other ways but notice that you propose none.

    If you need a set with specific iteration order or search
    criteria then you indeed can use 'boost::intrusive::set' or
    'boost::intrusive::multiset'. If you need a set with
    several iteration orders or search criteria then you
    can use 'boost::multi_index_container'. Those are not
    maps. Do not use 'map', 'multimap' or 'unordered_map'
    indeed if you just need 'set'.

    > I don't know if what Leigh wrote is correct, but if it is
    > that would be another strike against maps.


    Yes, it is correct about most implementations of vector.
    Those reserve automatically double bigger buffer when
    vector runs out of space. So benefit is log N and so
    the difference diminishes when N grows. If you want
    a map implementation based on vector then take
    'boost::flat_' (multi)map/set'.

    > Maps keep track of the number of elements in them. The
    > boost intrusive library gives you the option to not
    > have to pay for keeping track of the elements like that.


    Saving one integer value is questionable here. It is most
    likely that removing it is inefficient like with C string.
    C string is less efficient than 'std::string' on most of cases
    precisely because of not storing the length anywhere.
    So you need to show that you "pay", otherwise it might
    be empty claim.

    > I think unordered_map is a lame name.


    There is 'typedef' if you need better describing alias for type.
    Therefore "is a lame name" is not that convincing argument.
     
    Öö Tiib, Jan 15, 2014
    #15
  16. Luca Risolia

    Guest

    On Wednesday, January 15, 2014 10:01:54 AM UTC-6, Juha Nieminen wrote:
    > wrote:
    >
    > > I think the pair based interface is flawed and there should

    >
    > > instead be a container like Boost.intrusive.rbtree in the

    >
    > > standard. It wouldn't have to be intrusive, but it

    >
    > > wouldn't be pair based. Then you're able to work with one

    >
    > > type rather than two types. No more "first' and "second".

    >
    > > Multi_index doesn't use pair in its interface either.

    >
    >
    >
    > It almost sounds like you are talking about std::set.
    >
    > For most situations where you would use std::map, you can use std::set
    > instead, but to get the same functionality you have to design your
    > element type appropriately. std::map simply saves you the trouble
    > and gives you a handy shortcut when you need a type->type relational
    > data container.
    >


    I believe std::set has some const assumption that makes it
    difficult to use as an alternative.

    >
    > > I think unordered_map is a lame name.

    >
    > It's descriptive. What else do you want?
    >


    It isn't very descriptive. It's like saying a
    marble is not blue. Hash_map would be better.
    I think there was some history with that name,
    but think the name could still be changed to
    hash_map.

    Brian
    Ebenezer Enterprises
    http://webEbenezer.net
     
    , Jan 15, 2014
    #16
  17. Luca Risolia

    Öö Tiib Guest

    On Wednesday, 15 January 2014 18:50:53 UTC+2, wrote:
    > On Wednesday, January 15, 2014 10:01:54 AM UTC-6, Juha Nieminen wrote:
    > > wrote:
    > > > I think unordered_map is a lame name.

    > >
    > > It's descriptive. What else do you want?
    > >

    >
    > It isn't very descriptive. It's like saying a
    > marble is not blue. Hash_map would be better.


    Why? "Hash" sounds like Klingon/Orcish word
    while every child understands "unordered". On
    most cases the fact that unordered map is
    built internally on hash table is as unimportant
    as the fact that set is built upon red-black tree.

    > I think there was some history with that name,
    > but think the name could still be changed to
    > hash_map.


    When the requirements of standard are sufficiently
    different than those of prior art then it is good idea
    to rename. Same was with 'boost::scoped_ptr' that
    became 'std::unique_ptr'.
     
    Öö Tiib, Jan 15, 2014
    #17
  18. Luca Risolia

    Guest

    On Wednesday, January 15, 2014 11:32:44 AM UTC-6, Öö Tiib wrote:
    > On Wednesday, 15 January 2014 18:50:53 UTC+2, wrote:


    > >
    > > It isn't very descriptive. It's like saying a
    > > marble is not blue. Hash_map would be better.

    >
    > Why? "Hash" sounds like Klingon/Orcish word
    > while every child understands "unordered". On
    > most cases the fact that unordered map is
    > built internally on hash table is as unimportant
    > as the fact that set is built upon red-black tree.


    I believe unordered_map has to have a hash function.
    It defaults to std::hash if you don't supply your own.
    The Microsoft documentation on unordered_map says the
    sequence is "weakly ordered". That's a more accurate
    description than "unordered". But I don't like
    "weakly_ordered_map" for a name either. "Hash_map"
    is nice because it isn't so long.


    >
    > > I think there was some history with that name,
    > > but think the name could still be changed to
    > > hash_map.

    >
    > When the requirements of standard are sufficiently
    > different than those of prior art then it is good idea
    > to rename.


    What different requirements?

    Brian
    Ebenezer Enterprises
    http://webEbenezer.net
     
    , Jan 15, 2014
    #18
  19. Luca Risolia

    Guest

    On Wednesday, January 15, 2014 11:40:13 AM UTC-6, Mr Flibble wrote:
    >
    >
    > what I said about 'reserve' applied to vectors not maps; map doesn't
    > have a 'reserve'.
    >


    Oops. Thanks. I vaguely remember hearing discussion
    about adding reserve functions to some other containers,
    but I don't know if anything came of that.

    Brian
    Ebenezer Enterprises
    http://webEbenezer.net
     
    , Jan 15, 2014
    #19
  20. Luca Risolia

    Guest

    On Wednesday, January 15, 2014 10:20:06 AM UTC-6, Öö Tiib wrote:
    >
    > Saving one integer value is questionable here. It is most
    > likely that removing it is inefficient like with C string.
    > C string is less efficient than 'std::string' on most of cases
    > precisely because of not storing the length anywhere.
    > So you need to show that you "pay", otherwise it might
    > be empty claim.
    >


    Some containers you rarely/never need to know their size.


    Brian
    Ebenezer Enterprises
    http://webEbenezer.net
     
    , Jan 15, 2014
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. pmatos
    Replies:
    6
    Views:
    24,120
  2. Marcus
    Replies:
    2
    Views:
    620
    Marcus
    Dec 9, 2005
  3. Replies:
    8
    Views:
    1,998
    Csaba
    Feb 18, 2006
  4. Javier
    Replies:
    2
    Views:
    621
    James Kanze
    Sep 4, 2007
  5. Rushikesh Joshi
    Replies:
    0
    Views:
    394
    Rushikesh Joshi
    Jul 10, 2004
Loading...

Share This Page