【问题标题】:Sorting a std::map by value before output & destroy在输出和销毁之前按值对 std::map 进行排序
【发布时间】:2010-11-24 22:38:16
【问题描述】:

我知道地图尚未准备好进行排序。它针对快速和随机密钥访问进行了大量优化,实际上不支持std::sort

我目前的问题是我有一个完整的map<std::string,int>,我不会再使用它了。我只需要以value(int)的顺序提取10对并销毁即可。

如果可能的话,最好的办法是将它就地排序,然后迭代 10 次,但这显然不是解决方案。

我正在尝试不同的解决方案,例如通过 multimap<int,string>(允许重复键),但我想知道是否有更优雅的解决方案,尽可能使用 stl 算法。

编辑:

我使用地图是因为在 99% 的时间里,我都需要它作为地图:快速键查找以增加值。当我不再需要地图时,只需要一种稍后按值顺序提取的好方法。

目前的方法应该是:

  • std::copy map(std::string,int)vector(pair(std::string,int))
  • 对向量进行排序
  • 获取前 10 个值
  • 销毁矢量和地图

【问题讨论】:

  • 您的要求对我来说非常不清楚。 IIUC,您需要在地图中按它们的值而不是它们的键来查找 10 个条目吗?一旦你拥有它们,你将如何处理它们?我问是因为“破坏”是一个模糊的术语,我无法猜测std::pair<std::string,int> 的含义。是否要从地图中删除? (可能不需要,因为你说你不再需要地图了。但是还有什么?)
  • 地图将被销毁,所以我不在乎它以后会发生什么,只需要有这 10 个值

标签: c++ sorting dictionary stl


【解决方案1】:

地图存储为按键顺序排序的树。您想要 10 个最小(或最大)整数值及其键,对吗?

在这种情况下,迭代映射并将所有键值对放入对向量中(std::vector<std::pair<std::string, int> >)。我认为您可以为此使用 std::vector 的两个迭代器参数构造函数。然后在向量上使用std::partial_sort。为 partial_sort 指定一个比较器,它只通过比较值 int 来比较对,忽略键字符串。然后你在向量的开头有你想要的 10 对,剩下的向量包含未指定顺序的剩余对。

代码(未经测试):

typedef std::pair<std::string, int> mypair;

struct IntCmp {
    bool operator()(const mypair &lhs, const mypair &rhs) {
        return lhs.second < rhs.second;
    }
};


void print10(const std::map<std::string,int> &mymap) {
    std::vector<mypair> myvec(mymap.begin(), mymap.end());
    assert(myvec.size() >= 10);
    std::partial_sort(myvec.begin(), myvec.begin() + 10, myvec.end(), IntCmp());

    for (int i = 0; i < 10; ++i) {
        std::cout << i << ": " << myvec[i].first 
            << "-> " << myvec[i].second << "\n";
    }
}

请注意,如果有多个字符串具有相同的值,在 10 的限制的任一侧,则不指定您获得哪些字符串。在整数相等的情况下,您也可以通过让比较器查看字符串来控制这一点。

【讨论】:

    【解决方案2】:

    另一种可能性是构建反向地图。对你来说,那就是std::map&lt;int, std::string&gt;。反向映射中的条目按其值排序。

    以下是我的工具箱中用于此类场合的内容:

    template< typename TK, typename TV, class TP, class TA, typename T1, typename T2 >
    inline void asserted_insert(std::map<TK,TV,TP,TA>& m, const T1& k, const T2& v)
    {
      typedef std::map<TK,TV,TP,TA>                   map_type;
      typedef typename map_type::value_type           value_type;
      assert( m.insert(value_type(k,v)).second );
    }
    
    template< class TMap > struct reverse_map;
    template< typename T1, typename T2 > struct reverse_map< std::map<T1,T2> > {
      typedef std::map<T2,T1>                         result_t;
    };
    
    template< typename T1, typename T2, class TP1, class TA1, class TP2, class TA2 >
    inline void build_reverse_map(const std::map<T1,T2,TP1,TA1>& map, std::map<T2,T1,TP2,TA2>& reverse_map)
    {
      typedef std::map<T1,T2,TP1,TA1>                 map_type;
    
      for( typename map_type::const_iterator it=map.begin(),
                                            end=map.end(); it!=end; ++it ) {
        asserted_insert( reverse_map, it->second, it->first );
      }
    }
    

    此代码也假定值是唯一的(如果不是这种情况,则会抛出一个断言)。如果这不适用于您的问题,您可以轻松更改代码以使用多地图。

    【讨论】:

      【解决方案3】:

      如果您使用 map 迭代器进行迭代,您将获得按 key 排序的项目,因为它在内部使用平衡二叉树来存储值。因此,您可以使用迭代器从中提取 10 个值。这是你想要的还是你想做别的事情?请澄清。

      编辑: 不使用向量和排序,可以直接使用 set 并传递比较函数。然后您可以提取前 10 个元素。这是我的测试代码:

      typedef std::pair<std::string, int> MyPair;
      
      
      struct MyTestCompare
      {
      
          bool operator()(const MyPair& firstPair, const MyPair& secondPair) const
          {
              return firstPair.second < secondPair.second;
          }
      };
      
      int main()
      {
          std::map<std::string, int> m;
          m[std::string("1")] = 10;   
      m[std::string("2")] = 40;
      m[std::string("3")] = 30;
      m[std::string("4")] = 20;
      
      
      
          std::set<MyPair,MyTestCompare> s;
          std::map<std::string, int>::iterator iter = m.begin();
          std::map<std::string, int>::iterator endIter = m.end();
          for(; iter != endIter; ++iter)
          {
              s.insert(*iter);
          }
      
      }
      

      【讨论】:

      • “我只需要按值(int)顺序提取10对并销毁它。”
      • 你的地图是什么类型,即什么是键,什么是值?
      • 对不起,地图类型在问题正文中被转义了,我已经解决了。
      【解决方案4】:

      可能不是最优雅的方式,但您可以通过集合中的值对它们进行排序:

      #include #include #include #include 使用命名空间标准; 结构 sortPairSecond { bool operator()(const pair &lhs, const pair &rhs) { 返回 lhs.second myMap; 我的地图[“一个”] = 1; 我的地图[“十”] = 10; 我的地图[“五”] = 5; 我的地图[“零”] = 0; 我的地图[“八”] = 8; cout , sortPairSecond > mySet; for(map::const_iterator it = myMap.begin(); it != myMap.end(); ++it) { cout first second >::const_iterator it = mySet.begin(); it != mySet.end(); ++it) { cout first second

      【讨论】:

        【解决方案5】:

        对于按值迭代,您可以使用boost::multi_index。如下所示:

        #include <boost/multi_index_container.hpp>
        #include <boost/multi_index/member.hpp>
        #include <boost/multi_index/ordered_index.hpp>
        #include <boost/multi_index/hashed_index.hpp>
        using namespace boost::multi_index;
        
        struct X {
          X( std::string val_str, int val_int ) : val_str(val_str), val_int(val_int) {};
          std::string val_str;
          int         val_int;
        };
        
        typedef multi_index_container<
            X,
            indexed_by<
                hashed_unique< member<X, std::string, &X::val_str> >,
                ordered_non_unique< member<X, int, &X::val_int> >
            >
        > X_map;
        
        void func()
        {
           X_map data;
           data.insert( X("test", 1) );
           // ...
        
           // search by val_str 
           // complexity is equal to O(1) for hashed index (worst cast O(n) ), 
           // and O(log n) for ordered index
           X_map::const_iterator it = data.find( "test" );
           // ...
        
           // iterate in order of val_int
           size_t N = 0;
           for ( X_map::nth_index<1>::type::const_iterator it = data.get<1>().begin(); N < 10 && it != data.get<1>().end(); ++it, ++N ) {
             // copy elements somewhere
           }
        }
        

        您可以使用任何索引进行迭代(val_strval_int)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-09-05
          • 2019-05-03
          • 1970-01-01
          • 2014-04-03
          • 2013-03-02
          相关资源
          最近更新 更多