在c ++ stl map中,删除具有重复值的条目[关闭]

Posted

技术标签:

【中文标题】在c ++ stl map中,删除具有重复值的条目[关闭]【英文标题】:In c++ stl map, delete entries with duplicate values [closed] 【发布时间】:2018-05-16 09:10:32 【问题描述】:

考虑 map mymap 有条目

<'a', 111>  
<'b', 567>  
<'c', 956>  
<'d', 222>  
<'e', 111>  
<'f', 222>  
<'h', 222>  
<'i', 492> 

等等…… 如何删除地图中重复值的条目。 例如键 'a' 和 'e' 存在值 111。所以保留“a”的地图条目并删除“e”的条目 对于值 222,保留条目“d”并删除条目“f”和“h”。 我正在寻找具有最佳空间和时间复杂度的解决方案

【问题讨论】:

我投票决定将此问题作为离题结束,因为 SO 不是代码编写服务。请展示你的努力 构造一组值,如果该值已经在集合中,则从地图中删除该条目。 ~10-12 行代码。 "所以保留 'a' 的映射条目并删除 'e' 的条目" -- 为什么?为什么不保留“e”的地图条目并删除“a”的地图条目?您想要的规则也需要成为您问题的一部分。 @hvd 我想他想保留最低键的条目,但你是对的,这应该在问题中指定 @MichaelWalz "Lowest" 也未指定,因此需要在问题中解释 :) 在 ASCII 中,因此在大多数 C++ 实现中,'B' &lt; 'a',但这对于OP。 【参考方案1】:

这是一个有趣的问题,如果有点离题的话。

因为您的地图的值是可散列的且相等性可比的,所以我们可以在线性时间内执行此操作,使用unordered_set 来确定该值之前是否见过:

这段代码是c++17:

void comb(std::map<char, int>& themap)

    std::unordered_set<int> seen;
    seen.reserve(themap.size());

    // iterate through the map in key order...
    auto current = begin(themap);
    const auto last = end(themap);
    while(current != last)
    
        auto&&[key, value] = *current;

        // try to insert the value into the 'seen' set.
        if (seen.insert(value).second)
            // if we succeeded, then we're the first ocurrence of the
            // value so move to next node
            ++current;
        else
            // otherwise, erase this node and move to the next
            // (idiomatic method)
            current = themap.erase(current);
    

【讨论】:

【参考方案2】:

你可能想要这样的东西:

#include <iostream>
#include <map>
#include <set>

int main() 
  std::map<char, int> mymap
  
    'a', 111, 'b', 567, 'c', 956, 'd', 222, 
    'e', 111, 'f', 222, 'h', 222, 'i', 492,
  ;

  std::set<int> existingvalues;

  for (auto it = mymap.begin(); it != mymap.end(); it++)
  
    if (existingvalues.find(it->second) != existingvalues.end())
      mymap.erase(it--);                  // value already encountered => remove entry
    else
      existingvalues.insert(it->second);  // value not yet encountered => remeber it
  

  for (auto it = mymap.begin(); it != mymap.end(); it++)
    std::cout << "<'" << it->first << "', " << it->second << ">\n";

【讨论】:

【参考方案3】:

这是另一种可能的解决方案,涉及迭代地图容器 2 次,如果有重复值,第二次将有更少的元素来迭代:

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

template <typename T, typename U>
void RemoveDuplicateValues(std::map<T, U> &m)

    std::map<U, T> tmp;
    std::for_each(m.rbegin(), m.rend(), [&tmp](auto const &p)
    
        tmp[p.second] = p.first;
    );

    m.clear();
    for (auto const &p : tmp)
        m[p.second] = p.first;


int main()

    std::map<char, int> m
    
         'a', 111 , 'b', 567 , 'c', 956 , 'd', 222 ,
         'e', 111 , 'f', 222 , 'h', 222 , 'i', 492 
    ;

    RemoveDuplicateValues(m);

    // test
    for (auto const &p : m)
        std::cout << p.first << " " << p.second << std::endl;

    return 0;

演示:https://ideone.com/oThy17

a 111
b 567
c 956
d 222
i 492

【讨论】:

以上是关于在c ++ stl map中,删除具有重复值的条目[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MySQL 中删除具有几个相同值的行?

删除重复项,保留具有最大绝对值的条目

Java找到具有特定值的所有键[重复]

无法搜索具有重复值的条目

无法删除一个表中在另一个表中具有相应相关值的条目

如何在 MS Access 2003 中删除具有唯一 ID 的重复条目?