20

What's the best way in C++ to copy a pair from a map to vector? I'm doing this so I can subsequently sort the vector.

Jack BeNimble
  • 35,733
  • 41
  • 130
  • 213

7 Answers7

28
vector<pair<K,V> > v(m.begin(), m.end());

or

vector<pair<K,V> > v(m.size());
copy(m.begin(), m.end(), v.begin());

copy() is in <algorithm>.

wilhelmtell
  • 57,473
  • 20
  • 96
  • 131
  • 3
    This one seems to be more elegant and simple – Prabhu R Mar 26 '09 at 04:34
  • 1
    Yes, this is the best, especially the first one. Just a few explaining comments: If you have `typedef std::map MapType` you can't declare the vector `vector` as value_type is `pair` which has no operator= and can't be copied into the vector. Also, in the second example it is really important to pass the size of the vector first (either through the constructor or reserve) because copy will not allocate space in the vector as elements are added and there is a strong chance you will run over the end of the vector's initial allocation. – Christopher Howlin Dec 09 '10 at 11:29
  • 1
    `copy(m.begin(), m.end(), v.begin());` gave me a Segmentation Fault. Just saying. – yasith Feb 12 '12 at 21:14
  • @yasith You need to reserve the size of the vector or use back_inserter(). – Deepak Mohanty Sep 02 '18 at 03:03
  • @DeepakMohanty Actually you need to use vector::resize() or vector::reserve AND back_inserter(). – Virus_7 May 24 '21 at 11:08
24

This should do what you want:

#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <iterator>

using namespace std;

bool cmp(const pair<int, int>  &p1, const pair<int, int> &p2)
{
    return p1.second < p2.second;
}

int main()
{
    map<int, int> m;
    for(int i = 0; i < 10; ++i)
        m[i] = i * -i;

    vector<pair<int, int> > v;
    copy(m.begin(), m.end(), back_inserter(v));

    sort(v.begin(), v.end(), cmp);

    for(int i = 0; i < v.size(); ++i)
        cout << v[i].first << " : " << v[i].second << endl;
    return 0;
}
jmbpiano
  • 561
  • 3
  • 19
CTT
  • 16,901
  • 6
  • 41
  • 37
6

If you're using a std::map, it's already sorted by the key. Just create an iterator and iterate over the map from begin() to end() and you're done.

If you'd like to sort by something other than the map key, you can use the same iterator and push a copy of each element onto your vector as you iterate over the map.

Spire
  • 685
  • 6
  • 15
2

A map stores a pair -- a key and a value. Which part do you want to copy? Or, do you want to copy both to two distinct vectors?

I want to copy both. Once that's done, I need to figure out how to sort the vector by the second value in the pair.

template <class V>
struct sort_by_val {
  bool operator()(V const& l, V const& r) {
        return // ...
  }
};

vector<pair<K, V> > outv(map.begin(), map.end());

sort(outv.begin(), outv.end(), sort_by_val());
dirkgently
  • 108,024
  • 16
  • 131
  • 187
  • I want to copy both. Once that's done, I need to figure out how to sort the vector by the *second* value in the pair. – Jack BeNimble Mar 26 '09 at 04:06
  • +1, clear & simple solution. @Jack: you should really put the info in your comment into the main question as it's highly relevant -- e.g. it would have prevented everyone from mentioning that maps are already sorted by their first elements. – j_random_hacker Mar 26 '09 at 08:44
2

Assuming you want to copy the key and the value:

std::map<Foo, Bar> m;


// Map gets populated 
// (...)


// Copying it to a new vector via the constructor
std::vector<std::pair<Foo, Bar>> v(m.begin(), m.end());


// Copying it to an existing vector, erasing the contents
v.assign(m.begin(), m.end());

// Copying it to the back of an existing vector
v.insert(v.end(), m.begin(), m.end());
Andrew Shepherd
  • 44,254
  • 30
  • 139
  • 205
2

If your purpose is just to sort by the type instead of the key, you might want to look at Boost::Bimap. It lets you access both parts of the map pair as keys. Presumably you could iterate over it in order of the second key just as easily as the first.

Michael Kohne
  • 11,888
  • 3
  • 47
  • 79
0

You can use a different map (or set) and use transform to do the sorting as you insert:

#include <map>
#include <algorithm>

typedef std::map<unsigned int, signed char> MapType1;
typedef std::map<MapType1::mapped_type, MapType1::key_type> MapType2;

struct SwapPair
{
  MapType2::value_type operator()(MapType1::value_type const & v)
  {
    return std::make_pair (v.second, v.first);
  }
};

int main ()
{
  MapType1 m1;
  for(int i = 0; i < 10; ++i)
    m1[i] = i * -i;

  MapType2 m2;
  std::transform (m1.begin ()
      , m1.end ()
      , std::inserter (m2, m2.end ())
      , SwapPair ());
}

I forgot to add that if you need to do this a lot then it might be better just to use a boost multi-index container.

Richard Corden
  • 21,389
  • 8
  • 58
  • 85