creating a map from two vectors

只愿长相守 提交于 2019-12-29 06:56:13

问题


If I have two stl vectors vect1, vect2 and I want to produce from them a map, so first element from vect1 will correspond to first element in vect2 and so on. How can I do that in the most simple way?


回答1:


std::vector<int> a, b;
// fill vectors here...
std::map<int, int> m;
assert(a.size() == b.size());
for (size_t i = 0; i < a.size(); ++i)
    m[a[i]] = b[i];



回答2:


Here is a solution that uses standard library functions (and C++0x lambdas).

const int data1[] = { 0, 2, 4, 6, 8 };
const int data2[] = { 1, 3, 5, 7, 9 };
std::vector<int> vec1(data1, data1 + 5);
std::vector<int> vec2(data2, data2 + 5);
std::map<int,int> map;

// create map
std::transform(vec1.begin(), vec1.end(), vec2.begin(), std::inserter(map, map.end()), [](int a, int b)
{
    return std::make_pair(a, b);
});

// display map
std::for_each(map.begin(), map.end(), [](const std::pair<int,int>& p)
{
    std::cout << p.first << "," << p.second << "\n";
});

Note: This assumes vec1.size() is not greater than vec2.size().




回答3:


We will use the version of std::transform that takes 2 input sequences. (Not as well known it appears as the one that takes a single sequence).

You can pass in std::make_pair<v1::value_type, v2::value_type> as your transformer (op) thus in your case

std::vector<int> vec1, vec2;
std::map< int, int > mergedMap;
std::transform( vec1.begin(), vec1.end(), vec2.begin(), 
       std::inserter(mergedMap, mergedMap.end() ), std::make_pair<int const&,int const&> );

I have tested the code and it compiles fine with GNU 4.3.2

(I have also tested now with C++11. It works when I changed make_pair to take int const& rather than int).

If the two input sequences are of different length, it will be fine if the first is shorter, and later elements in the second sequence will be ignored. If the first is longer, it will produce undefined behaviour.




回答4:


Here is a slight variation that uses boost's zip_iterator

#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <vector>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>

// this is our map type
typedef std::map<int, std::string> map_t;

// this functor will be called for each "pair"
struct map_adder :
  public std::unary_function<const boost::tuple<const int&, const std::string&>&, void>
{
  map_adder(map_t& my_map) : _my_map(my_map){}

  void operator()(const boost::tuple<const int&, const std::string&>& t) const
  {
    _my_map.insert(std::make_pair(t.get<0>(), t.get<1>()));
  }

private:
  mutable map_t& _my_map;
};

int main(void)
{
  // test setup
  std::vector<int> keys;
  std::vector<std::string> values;
  keys.push_back(1);
  keys.push_back(2);
  keys.push_back(3);
  keys.push_back(4);

  values.push_back("1");
  values.push_back("2");
  values.push_back("3");
  values.push_back("4");

  std::vector<int>::const_iterator beg1 = keys.begin();
  std::vector<int>::const_iterator end1 = keys.end();
  std::vector<std::string>::const_iterator beg2 = values.begin();
  std::vector<std::string>::const_iterator end2 = values.end();

  // destination
  map_t my_map;

  // functor to actually add
  map_adder adder(my_map);

  // simply iterate over...
  std::for_each(
    boost::make_zip_iterator(
      boost::make_tuple(beg1, beg2)
      ),
    boost::make_zip_iterator(
      boost::make_tuple(end1, end2)
      ),
    adder
  );

  std::cout << "size of map: " << my_map.size() << std::endl;

  return 0;
}

okay, here is a simpler version using std::transform, I'm not aware of something which already exists which can convert a boost::tuple to a std::pair hence my simple function...

#include <iostream>
#include <algorithm>
#include <string>
#include <iterator>
#include <map>
#include <vector>
#include <boost/iterator/zip_iterator.hpp>
#include <boost/tuple/tuple.hpp>

// this is our map type
typedef std::map<int, std::string> map_t;

map_t::value_type adapt_tuple(const boost::tuple<const map_t::key_type&, const map_t::mapped_type&>& t)
{
  return map_t::value_type(t.get<0>(), t.get<1>());
}

int main(void)
{
  std::vector<int> keys;
  std::vector<std::string> values;
  keys.push_back(1);
  keys.push_back(2);
  keys.push_back(3);
  keys.push_back(4);

  values.push_back("1");
  values.push_back("2");
  values.push_back("3");
  values.push_back("4");

  std::vector<int>::const_iterator beg1 = keys.begin();
  std::vector<int>::const_iterator end1 = keys.end();
  std::vector<std::string>::const_iterator beg2 = values.begin();
  std::vector<std::string>::const_iterator end2 = values.end();

  map_t my_map;

  // simply iterate over...
  std::transform(
    boost::make_zip_iterator(
      boost::make_tuple(beg1, beg2)
      ),
    boost::make_zip_iterator(
      boost::make_tuple(end1, end2)
      ),
    std::inserter(my_map, my_map.end()),
    adapt_tuple
    );

  std::cout << "size of map: " << my_map.size() << std::endl;

  return 0;
}



回答5:


assuming, you are going to ignore the extra (size of vect1 != size of vect2), this could be a solution:

map<T1, T2> target; //vector<T1> vect1, vector<T2> vect2;
vector<T1>::iterator it1 = vect1.begin();
vector<T2>::iterator it2 = vect2.begin();
while(it1 != vect1.end() && it2 != vect2.end())
{
target.insert(std::make_pair(*it1, *it2));
it1++;it2++;
}

EDIT : Thanks Nim for pointing out *it1 thing.



来源:https://stackoverflow.com/questions/4946424/creating-a-map-from-two-vectors

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!