簡體   English   中英

擦除 std::map 中的特定元素

[英]Erase specific elements in std::map

我想刪除我的 std::map 中的一些元素。
我編寫了擦除 + remove_if 技術,我總是使用其他序列容器。
但它不是用 map 編譯的。 為什么?
我該如何做這份工作?

std::map<int, int> m;

bool foo(const std::pair<int, int>& p)
{
    return p.second > 15;
}

int _tmain(int argc, _TCHAR* argv[])
{
    m.insert(make_pair(0, 0));
    m.insert(make_pair(1, 10));
    m.insert(make_pair(2, 20));
    m.insert(make_pair(3, 30));

    m.erase(
        remove_if(m.begin(), m.end(), foo),
        m.end()); // compile error

    return 0;
}

像這樣為 map 編寫它,因為remove_if不適用於map迭代器(它只是將有問題的元素放在最后,而map迭代器不允許這樣做):

template <typename Map, typename F>
void map_erase_if(Map& m, F pred)
{
    typename Map::iterator i = m.begin();
    while ((i = std::find_if(i, m.end(), pred)) != m.end())
        m.erase(i++);
}

或者如果你喜歡單線:

template <typename Map, typename F>
void map_erase_if(Map& m, F pred)
{
    for (typename Map::iterator i = m.begin();
         (i = std::find_if(i, m.end(), pred)) != m.end();
         m.erase(i++));
}

因為std::map不是“序列容器”:) remove_if將嘗試將無用的元素放在 map 的末尾,但這會導致違反 map 的隱式數據結構(大多數情況下是紅黑樹) . 隱式數據結構定義了 map 中每個元素的位置,這就是為什么std::map不允許remove_if的原因。

您應該在循環中一個接一個(或給出一些間隔)從std::map中刪除元素。

像這樣的東西:

it = m.begin();
while ((it = std::find_if(it, m.end(), pred)) != m.end())
    m.erase(it++);

“使用其他序列容器”是您的錯誤 - map是一個關聯容器,在關聯容器中,元素由它們的鍵定義(與它們在序列容器中的插入順序相反),並且您通過鍵擦除元素:

m.erase(12);

按鍵值擦除與查找具有相同的復雜性(例如,對於 map,O(log n),對於無序 map,O(1),等等)。 或者,您可以在恆定時間內通過迭代器擦除。 擦除迭代器會使該迭代器無效,但不會使其他迭代器無效(再次與序列容器不同),因此如果您想迭代 map,典型的習慣用法是這樣的:

for (auto it = m.cbegin(); it != m.cend(); ) // no "++"!
{
  if (it->second > 15)  // your own condition goes here
  {
    m.erase(it++);
  }
  else
  {
    ++it;
  }
}

此成語僅適用於類似容器的序列 - map(關聯)中的條目不能重新排序(密鑰不會改變 - 所以你怎么可能期望將條目移動到其他一些 position - 例如結束)。 正確的方法是找到條目並將其刪除 - 即it = map.find(); map.erase(it++) it = map.find(); map.erase(it++)

但它不是用 map 編譯的。 為什么?

使用remove_if時,解引用迭代器的類型必須滿足 CopyAssignable 的要求。 也就是說,應該可以將一個值分配給另一個值。

對於std::map<int, int>值是std::pair<const int, int> ,它表示 map 的鍵值對並且不是 CopyAssignable。 這個const int for key 的原因是 map 在內部如何工作,正如其他人已經指出的那樣。

順便說一句,您將得到與序列容器相同的編譯錯誤,如下所示:

std::vector<std::pair<const int, int>>;

嘗試這樣的事情

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

class foo 
{
public:
    enum CompType { GREATER=1, LESS=-1 };
    foo(int nVal=15, enum CompType ctype=GREATER)
    : m_nVal(nVal)
    , m_bGreater(ctype==GREATER)
    {
    }
    bool operator()(std::pair<int, int> p) 
    {
        if (m_bGreater)
            return p.second > m_nVal;
        else
            return p.second < m_nVal;
    }
private:
    int  m_nVal;
    bool m_bGreater;
};

void MapRemove(std::map<int, int> &m, foo &pred)
{
    auto itr = std::find_if(m.begin(), m.end(), pred);
    while (itr != m.end())
        itr = std::find_if(m.erase(itr), m.end(), pred);
}

int main(int argc, char *argv[])
{
    std::map<int, int> m;

    m.insert(std::make_pair(0, 0));
    m.insert(std::make_pair(1, 10));
    m.insert(std::make_pair(2, 20));
    m.insert(std::make_pair(3, 30));

    MapRemove(m, foo());

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

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM