【问题标题】:Sorting std::unordered_map by key按键排序 std::unordered_map
【发布时间】:2011-06-02 09:20:44
【问题描述】:

如何按键对unordered_map 进行排序?我需要打印一个按键排序的unordered_map

【问题讨论】:

    标签: c++ sorting unordered-map


    【解决方案1】:
    std::unordered_map<int, int> unordered;
    
    std::map<int, int> ordered(unordered.begin(), unordered.end());
    for(auto it = ordered.begin(); it != ordered.end(); ++it)
         std::cout << it->second;
    

    【讨论】:

    • 我已将 unorderedmap 声明为 std::unordered_map&lt;int, unsigned long&gt; *myunorderedmap;std::map&lt;int, unsigned long&gt; ordered(myunorderedmap-&gt;begin, myunorderedmap-&gt;end); 给出错误
    • begin 和 end 是函数。使用ordered(myunorderedmap-&gt;begin(), myunorderedmap-&gt;end()) 而不是您使用的,一切都会好起来的。
    • 别忘了,如果你不关心保留初始容器中的元素,可以使用make_move_iterator将元素移动到新容器中:std::map&lt;int, int&gt; ordered(std::make_move_iterator(unordered.begin()), std::make_move_iterator(unordered.end()));
    【解决方案2】:

    另一种解决方案是构造一个键向量,对向量进行排序,然后按排序后的向量进行打印。这将比从有序地图构建地图的方法快得多,但也会涉及更多代码。

    std::unordered_map<KeyType, MapType> unordered;
    std::vector<KeyType> keys;
    
    keys.reserve (unordered.size());
    for (auto& it : unordered) {
        keys.push_back(it.first);
    }
    std::sort (keys.begin(), keys.end());
    for (auto& it : keys) {
        std::cout << unordered[it] << ' ';
    }
    

    【讨论】:

    • 如果你使用向量和std::sort而不是列表会更快。
    • 如果您保留所需长度的向量(如果您必须使用 push_back),甚至会稍微快一点
    • @Steven Lu 如果你不关心订单,你可以用什么来代替push_back,就像这个例子一样?
    【解决方案3】:

    确定你需要这个吗?因为那是不可能的。 unordered_map 是一个散列容器,即键是散列。在容器内部,它们与外部的表示不同。甚至名称也暗示您无法对其进行排序。这是选择哈希容器的标准之一:您确实不需要需要特定的顺序。

    如果您这样做,请获取普通的map。键自动按严格-弱排序进行排序。如果您需要其他排序,请编写自己的比较器。

    如果您只需要将其打印排序,以下可能效率低下,但如果您仍想保留unordered_map,它会尽可能接近。

    #include <map>
    #include <unordered_map>
    #include <algorithm>
    #include <iostream>
    #include <functional>
    
    struct map_streamer{
      std::ostream& _os;
    
      map_streamer(std::ostream& os) : _os(os) {}
    
      template<class K, class V>
      void operator()(std::pair<K,V> const& val){
        // .first is your key, .second is your value
        _os << val.first << " : " << val.second << "\n";
      }
    };
    
    template<class K, class V, class Comp>
    void print_sorted(std::unordered_map<K,V> const& um, Comp pred){
      std::map<K,V> m(um.begin(), um.end(), pred);
      std::for_each(m.begin(),m.end(),map_streamer(std::cout));
    }
    
    template<class K, class V>
    void print_sorted(std::unordered_map<K,V> const& um){
      print_sorted(um, std::less<int>());
    }
    

    Example on Ideone.
    请注意,在 C++0x 中,您可以将两个重载替换为一个带有默认模板参数的函数:

    template<class K, class V, class Comp = std::less<int> >
    void print_sorted(std::unordered_map<K,V> const& um, Comp pred = Comp()){
      std::map<K,V> m(um.begin(), um.end(), pred);
      std::for_each(m.begin(),m.end(),map_streamer(std::cout));
    }
    

    【讨论】:

    • 您可以使用std::ostream_iteratorstd::copy 代替您自己的streamer 东西。
    • @Itjax:再想一想,不,因为std::for_each 会给我一个std::pair&lt;K,V&gt;,无论如何我都需要拆分它。由于这个原因,我的第一个实现不起作用,std::pair 无法流式传输。
    【解决方案4】:

    与大卫的回答类似,我们可以先使用std::set 对键进行排序:

    std::unordered_map<int, int> unordered;
    std::set<int> keys;
    for (auto& it : unordered) keys.insert(it.first);
    for (auto& it : keys) {
        std::cout << unordered[it] << ' ';
    }
    

    【讨论】:

      【解决方案5】:

      你可以使用vector来存储你的键值对,然后在vector中排序,最后放回map。

      #include <iostream>                                 
      #include <unordered_map>                                 
      #include <algorithm>                                 
      #include <vector>                                 
      
      using namespace std;                                
      
      int main(){                                
          unordered_map<string, int> sdict = {{"hello", 11 }, {"world", 52}, {"tommy", 3}};               
          unordered_map<string, int> resdict;          
      
          vector<pair<string, int>> tmp;
          for (auto& i : sdict)                                         
              tmp.push_back(i);                                
      
          for (auto& i : sdict)       
              cout <<  i.first << " => " << i.second << endl;  
      
          // sort with descending order.
          sort(tmp.begin(), tmp.end(),                                   
          [&](pair<string, int>& a, pair<string, int>& b) { return a.second < b.second; });
      
          for (auto& i : tmp)                          
          {                           
              resdict[i.first] = i.second;                   
          }                                
      
          cout << "After sort." << endl;   
          for (auto& i : resdict)     
              cout <<  i.first << " => " << i.second << endl;           
          return 0;                                              
      
      }                                            
      

      使用以下命令编译。

      g++ --std=c++11 test_sort_ordered_map.cpp
      

      结果是:

      tommy => 3
      hello => 11
      world => 52
      After sort.
      world => 52
      hello => 11
      tommy => 3
      

      【讨论】:

        猜你喜欢
        • 2011-12-28
        • 1970-01-01
        • 2013-11-19
        • 1970-01-01
        • 2012-07-09
        • 1970-01-01
        • 1970-01-01
        • 2014-04-30
        • 1970-01-01
        相关资源
        最近更新 更多