【问题标题】:How can I get all the unique keys in a multimap如何获取多图中的所有唯一键
【发布时间】:2012-07-18 06:56:01
【问题描述】:

我有一个多重映射,我希望将其中的所有唯一键存储在一个向量中。

  multimap<char,int> mymm;
  multimap<char,int>::iterator it;
  char c;

  mymm.insert(pair<char,int>('x',50));
  mymm.insert(pair<char,int>('y',100));
  mymm.insert(pair<char,int>('y',150));
  mymm.insert(pair<char,int>('y',200));
  mymm.insert(pair<char,int>('z',250));
  mymm.insert(pair<char,int>('z',300));

我该怎么做?有办法用一个键计算元素的数量,但没有办法计算多重映射中唯一键的数量。

添加:唯一是指多图中的所有键一次 - 它们可以在多图中重复或出现一次。

这里的唯一键是 - xyz

【问题讨论】:

标签: c++ stl std multimap


【解决方案1】:

我试过了,效果很好

for(  multimap<char,int>::iterator it = mymm.begin(), end = mymm.end(); it != end; it = mymm.upper_bound(it->first))
  {
      cout << it->first << ' ' << it->second << endl;
  }

【讨论】:

  • 它将打印所有元素
  • @AJ 见upper_bound 部分,这应该只打印每个键一次
  • 它涉及在每次迭代时搜索整个地图。
  • 我在upper_bound 上收到了弃用警告,提示使用equal_range().second。改成之后,一切正常。
【解决方案2】:

由于 std::multimap&lt;&gt; 的条目是隐式排序的,并且在遍历它们时按排序顺序出现,因此您可以为此使用 std::unique_copy 算法:

#include <iostream>
#include <map>
#include <algorithm>
#include <vector>

using namespace std;

int main() {

  /* ...Your existing code... */

  /* Create vector of deduplicated entries: */
  vector<pair<char,int>> keys_dedup;
  unique_copy(begin(mymm),
              end(mymm),
              back_inserter(keys_dedup),
              [](const pair<char,int> &entry1,
                 const pair<char,int> &entry2) {
                   return (entry1.first == entry2.first);
               }
             );

  /* Print unique keys, just to confirm. */
  for (const auto &entry : keys_dedup)
    cout << entry.first << '\n';

  cout.flush();
  return 0;
}

由此增加的额外工作与多重映射的条目数量呈线性关系,而使用std::set 或 Jeeva 的重复数据删除方法都增加了 O(n log n) 计算步骤。

备注: 我使用的 lambda 表达式假定为 C++11。可以为 C++03 重写。

【讨论】:

  • 为什么 std::multimap 没有包含所有唯一键的简单向量/列表/集合/映射。这似乎很有用,而且开销也不大。这个功能不存在是因为人们不会那么多使用这个功能,还是因为开销比我想象的要多?我不认为空间是必需的(对吗?)。
  • @Fractal 我不确定我是否完全理解您的建议。一个额外的数据结构会占用 O(n) 额外的空间,不是吗?不过,最好的一件事是一个接口(例如一个特殊的迭代器),它将一个一个地返回唯一键。
  • 是的,是的……这将是 O(n) 额外的空间。我不认为空间实际上是一个问题,但也许在我的工作中我没有处理足够大的数据组来理解这将是一个压力/问题。是的,一个特殊的迭代器是理想的。
  • 但是您不仅存储了问题中所需的密钥...您到底存储了什么?
  • 我不确定这是否比@jeeva 的方法更有效。对于我的数据集,我的基准测试表明这需要大约 1-2 秒,而 Jeeva 的方法需要 0.3 秒。我有大约 470 万个值,其中 3642 个是唯一的
【解决方案3】:

遍历mymm的所有元素,并将it-&gt;first存储在set&lt;char&gt;中。

【讨论】:

  • -1。它不会给出唯一的键。它将提供所有密钥。例如,如果有两个键“a”,您的集合中将有键“a”,但它不是唯一的
  • @Andrew set 只会保留独特的元素。它给出唯一的键。
  • +1 正如我刚刚在另一个答案中使用集合作为评论所写的那样! ;)
  • @Andrew 编辑:独特意味着每一种。如果 multimap 中有两个 'a' 键,则唯一集必须包含一个 'a'
  • 我同意这两种解释都是可能的。抱歉,在编辑答案之前无法删除 -1
【解决方案4】:

最简单的方法是将 multimap 的键放在 unordered_set 中

unordered_multimap<string, string> m;

//insert data in multimap

unordered_set<string> s;         //set to store the unique keys

for(auto it = m.begin(); it != m.end(); it++){
    if(s.find(it->first) == s.end()){
        s.insert(it->first);
        auto its = m.equal_range(it->first);
        for(auto itr=its.first;itr!=its.second;itr++){
            cout<<itr->second<<" ";
        }
    }
}

【讨论】:

    【解决方案5】:

    如果unique 是指multimap 中包含的密钥仅一次,我认为您可以这样做:

    1) 为您的地图中的所有键构造一个已排序的list

    2) 遍历列表并找到唯一键。这很简单,因为所有重复项将在排序容器中彼此靠近

    如果您只想要所有键 - 按照 Donotalo 的建议使用 std::set

    【讨论】:

    • 为什么使用排序列表而不是集合?该集合已经证明是唯一性的。
    • @MareInfinitus:因为如果多图中有两个键“a”,那么键“a”将在集合中,但它不是唯一的
    • a 是一个密钥,即使多次使用,它仍然是一个必须存储的密钥。至少我理解这个问题不想要一个不多次使用的键列表,而是一个键列表。
    【解决方案6】:

    其他选项是将它们插入向量中,然后使用 std::sortstd::unique

    template<typename Container> static
    std::vector<typename Container::key_type> unique_keys(Container A)
    {
    
        using ValueType = typename Container::key_type;
    
        std::vector<ValueType> v;
    
        for(auto ele : A)
        {
            v.push_back(ele.first);
        }
    
        std::sort(v.begin(), v.end());
        auto it = std::unique(v.begin(), v.end());
        v.resize(distance(v.begin(),it));
    
        return v;
    }
    

    【讨论】:

      【解决方案7】:

      这可以在 O(N) 中完成,其中 N 是地图的大小;您的密钥不需要有订单运算符:

      template<typename Container>
      std::vector<typename Container::key_type> UniqueKeys (const Container &A)
      {
      std::vector<typename Container::key_type> v;
      auto prevIter = A.begin ();
      
      for (auto iter = A.begin (); iter != A.end(); ++iter)
          {
          if (prevIter->first == iter->first)
              continue;
      
          v.push_back (prevIter->first);
          prevIter = iter;
          }
      
      if (prevIter != A.end ())
          v.push_back (prevIter->first);
      
      return v;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多