【问题标题】:Possible: Set Operations on Disparate Maps with Same Key Type?可能:在具有相同键类型的不同地图上设置操作?
【发布时间】:2010-03-23 22:46:03
【问题描述】:

假设我有两张地图:

typedef int Id;
std::map<Id, std::string> idToStringMap;
std::map<Id, double>      idToDoubleMap;

假设我想对两张地图的键进行集合操作。 有比创建自定义“插入器”迭代器更简单的方法吗?这样我就可以执行以下操作:

std::set<Id> resultSet;
set_difference( idToStringMap.begin(), idToStringMap.end(), 
                idToDoubleMap.begin(), idToDoubleMap.end(), resultSet.begin() );

我的实验结果表明,有必要创建一个自定义插入器,也许还有一个自定义键比较器来执行此操作,但在此之前我想要一些见解/捷径。

【问题讨论】:

    标签: c++ stl map set


    【解决方案1】:

    我认为仅使用没有自定义迭代器的 stl 是不可能的。您应该创建一个通用的select_1st_iterator。这会将任何迭代器包装成一对并在取消引用时返回 itr->first。

    注意:对 stl 的一些扩展有一个 select1st 函子,它接受一对并返回第一个元素。但是我还没有看到迭代器版本。

    如果您打算编写一个迭代器,我建议您使用boost iterator libraryselect_1st_iterator 最有可能的候选者是 transfor_iterator

    假设 select_1st_iterator 是一个创建真正的 select_1st_iterator_t 类型的函数,它可能看起来像:

    注意:如果您不对resultSet 使用insert_iterator,您的代码将会崩溃

    template<class T>
    select_1st_iterator_t<T> select_1st_iterator<T>(itr)
    {
        return select_1st_iterator_t<T>(itr);
    }
    
    std::set<Id> resultSet;
    set_difference(
        select_1st_iterator(idToStringMap.begin()), 
        select_1st_iterator(idToStringMap.end()),
        select_1st_iterator(idToDoubleMap.begin()),
        select_1st_iterator(idToDoubleMap.end()),
        std::inserter(resultSet, resultSet.begin()) );
    

    【讨论】:

    • 谢谢!关于 boost 迭代器库的信息和对 transform_iterator 的提示使我免于浪费精力。 :)
    【解决方案2】:

    我使用 iain 的建议的解决方案:

    template <typename T>
    class Select1st 
     : public std::unary_function<T&,typename T::first_type>
    {
         public:
             int operator() (T & value) const 
             {
                 return value.first;
             }
    };
    
    template <typename T>
    class KeyGrabItorAdapter 
     : public boost::transform_iterator< Select1st<typename T::value_type>,
                                                        typename T::iterator >
    {
        public:
            KeyGrabItorAdapter( typename T::iterator itor )
                : boost::transform_iterator<Select1st<typename T::value_type>,
                                                           typename T::iterator>
                      ( itor, Select1st<typename T::value_type>() )         
            {
            }
    
    };
    

    具有前面允许以下内容:

    typedef std::map<int, int>    IntToIntMap;
    IntToIntMap    intToIntMapA;
    IntToIntMap    intToIntMapB;
    
    typedef std::map<int, double> IntToDoubleMap;
    IntToDoubleMap intToDoubleMapA;
    IntToDoubleMap intToDoubleMapB;
    
    KeyGrabItorAdapter<IntToIntMap>    grabFirstABegin(    intToIntMapA.begin() ) ;
    KeyGrabItorAdapter<IntToIntMap>    grabFirstAEnd(      intToIntMapA.end()   ) ;
    KeyGrabItorAdapter<IntToDoubleMap> grabFirstBBegin( intToDoubleMapB.begin() ) ;
    KeyGrabItorAdapter<IntToDoubleMap> grabFirstBEnd(   intToDoubleMapB.end()   ) ;
    
    std::set<int> intResultSet;
    
    set_difference( grabFirstABegin, grabFirstAEnd,
                    grabFirstBBegin, grabFirstBEnd,
                        inserter( intResultSet, intResultSet.begin()),
                            intToIntMapA.key_comp() );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-27
      相关资源
      最近更新 更多