Search code examples
c++dictionaryinsertion

C++: inserting into a boost::unordered_map from key and value vectors


I have two std::vector<std::string>. One contains field names; the other contains the corresponding values. What is the best way to insert all fieldname / value pairs into a boost::unordered_map?

I could certainly obtain two iterators on the vectors and loop through, inserting one pair on each iteration, but I wondered if there were a simpler way.

UPDATE 1: Additional info: I have g++ 4.4, so I have no access to most of the c++11 goodies.

UPDATE 2: based on @chris's suggestion I am trying to use boost::iterator. Here is the example from the Boost documentation that I'm using:

std::vector<double>::const_iterator beg1 = vect_of_doubles.begin();
std::vector<double>::const_iterator end1 = vect_of_doubles.end();
std::vector<int>::const_iterator beg2 = vect_of_ints.begin();
std::vector<int>::const_iterator end2 = vect_of_ints.end();

std::for_each(
  boost::make_zip_iterator(
    boost::make_tuple(beg1, beg2)
    ),
  boost::make_zip_iterator(
    boost::make_tuple(end1, end2)
    ),
  zip_func()
  );
A non-generic implementation of zip_func could look as follows:

struct zip_func :
  public std::unary_function<const boost::tuple<const double&, const int&>&, void>
{
  void operator()(const boost::tuple<const double&, const int&>& t) const
  {
    m_f0(t.get<0>());
    m_f1(t.get<1>());
  }

private:
  func_0 m_f0;
  func_1 m_f1;
};

I understand everything up to the definition of zip_func(). Where should the struct live? Should it return anything? Why is there a operator()? There's too much going on there for me to get my head around. For my problem, how would the zip_func() extract the field name and value and insert it into an unordered_map?


Solution

  • You are close. In the example above, zip_func is the functor that you provide that does the work you want it to. In this case, something like:

    typedef unordered_map<string,string> stringmap;
    
    struct map_insertor {
        void operator()(const boost::tuple<const string&, const string&> &t ) {
            m_map.insert(make_pair(t.get<0>(),t.get<1>());
        }
        map_insertor(stringmap &m) : m_map(m) {}
        private:
            stringmap &m_map;
    };
    
    stringmap my_map;
    for_each( 
        boost::make_zip_iterator(
            boost::make_tuple(beg1, beg2)
        ),
        boost::make_zip_iterator(
            boost::make_tuple(end1, end2)
        ),
        map_insertor(my_map)
    );
    

    But there is nothing wrong with the simple solution.

    typedef vector<string> stringvec;
    
    stringvec::iterator ik = vec_of_keys.begin();
    stringvec::iterator iv = vec_of_vals.begin();
    for( ;(ik != vec_of_keys.end()) && (iv != vec_of_vals.end()); ik++,iv++) {
      my_map.insert(make_pair(*ik, *iv));
    }