C++如何将一个map复制到一个vector

20

在C ++中,从map复制一个pair到vector的最佳方法是什么?我这样做是为了随后对vector进行排序。


1
地图已经排序。您应该指定是否要按另一个参数或使用不同的键进行排序。否则,问题就是自我回答的:不要排序。 - David Rodríguez - dribeas
1
因为几位人士认为(更新的)重复内容更高质量,所以将其作为重复关闭。 - Drew Dormann
7个回答

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

copy() 函数位于 <algorithm> 头文件中。


3
这个看起来更加优美简洁。 - Prabhu R
1
是的,这是最好的,特别是第一个。只有一些解释性的注释:如果你有 typedef std::map<K,V> MapType,你不能声明向量 vector<MapType::value_type>,因为 value_type 是 pair<const K, V>,它没有 operator=,也不能被复制到向量中。此外,在第二个示例中,通过构造函数或保留传递向量的大小真的很重要,因为复制不会在向量中分配空间,因为元素被添加时,有很大的机会超过向量初始分配的末尾。 - Christopher Howlin
1
copy(m.begin(), m.end(), v.begin()); 给我一个分段错误。只是说一下。 - yasith
@yasith 你需要预留向量的大小或使用back_inserter()。 - Deepak Mohanty
@DeepakMohanty 实际上你需要使用 vector::resize() 或 vector::reserve 以及 back_inserter()。 - Virus_7

24

这应该能够满足你的需求:

#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;
}

6

如果你正在使用std::map,它已经按键排序。只需创建一个迭代器并从begin()到end()遍历该映射即可。

如果您想按除地图键以外的其他内容进行排序,可以使用相同的迭代器,并在遍历地图时将每个元素的副本推送到您的向量中。


可能更简单的方法是:您可以在映射的构造函数中指定一个比较器。 - foraidt

2
如果您的目的仅是按类型而不是键进行排序,您可能需要查看Boost::Bimap。它允许您访问映射对的两个部分作为键。您可以像第一个键一样轻松地按第二个键的顺序迭代它。

2

map 存储一对键值对。您想复制哪一部分?或者,您想将两个部分都复制到两个不同的 vector 中吗?

我想要复制两个部分。完成后,我需要弄清楚如何按照键值对中的第二个值对向量进行排序。

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

我想要复制两个。完成后,我需要弄清楚如何按对中的第二个值对向量进行排序。 - Jack BeNimble
+1,清晰简洁的解决方案。@Jack:你应该将评论中的信息放入主要问题中,因为它非常相关 - 例如,这将防止每个人都提到地图已经按其第一个元素排序。 - j_random_hacker

2
假设您想复制键和值:
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());

最后一个是不正确的。也许你的意思是v.insert(v.rbegin().base(), m.begin(), m.end());? - wilhelmtell
你为什么认为它不正确?我刚试过了,它运行得很好。 - Andrew Shepherd
想一想:v.rebegin().base() 返回的迭代器与 v.end() 相同。 - Andrew Shepherd
如果v.size() >= 1的话应该是没问题的。范围是从位置迭代器前面的元素插入的。 - Functastic
感谢您提供最佳的语法片段(例如v.assign行)。 - anon
显示剩余2条评论

0

你可以使用不同的映射(或集合),并使用 transform 在插入时进行排序:

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

我忘了补充一点,如果你需要经常这样做,那最好使用一个boost multi-index容器。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接