[英]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.