开发者

creating a map from two vectors

开发者 https://www.devze.com 2023-02-09 18:33 出处:网络
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.

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 tha开发者_运维技巧t in the most simple way?


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


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];


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.


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


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号