从满足谓词的无序映射中删除元素
Posted
技术标签:
【中文标题】从满足谓词的无序映射中删除元素【英文标题】:Remove Elements from an Unordered Map Fulfilling a Predicate 【发布时间】:2012-02-09 11:25:11 【问题描述】:我想从std::unordered_map
(直方图)中删除满足作为 lambda 表达式给出的预测(计数为零的直方图箱)的元素(直方图箱),如下所示
std::remove_if(begin(m_map), end(m_map), [](const Bin & bin) return bin.second == 0; );
但是 GCC-4.6.1 抱怨如下
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const unsigned char, unsigned char>::first’
/usr/include/c++/4.6/bits/stl_pair.h: In member function ‘std::pair<_T1, _T2>& std::pair<_T1, _T2>::operator=(std::pair<_T1, _T2>&&) [with _T1 = const unsigned char, _T2 = long unsigned int, std::pair<_T1, _T2> = std::pair<const unsigned char, long unsigned int>]’:
/usr/include/c++/4.6/bits/stl_algo.h:1149:13: instantiated from ‘_FIter std::remove_if(_FIter, _FIter, _Predicate) [with _FIter = std::__detail::_Hashtable_iterator<std::pair<const unsigned char, long unsigned int>, false, false>, _Predicate = pnw::histogram<V, C, H>::pack() [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]::<lambda(const Bin&)>]’
tests/../histogram.hpp:68:13: instantiated from ‘void pnw::histogram<V, C, H>::pack() [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’
tests/../histogram.hpp:85:13: instantiated from ‘void pnw::histogram<V, C, H>::normalize(uint) [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >, uint = unsigned int]’
tests/../histogram.hpp:121:51: instantiated from ‘H& pnw::histogram<V, C, H>::add(It, It) [with It = __gnu_cxx::__normal_iterator<const unsigned char*, std::vector<unsigned char> >, V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’
tests/../histogram.hpp:129:55: instantiated from ‘H& pnw::histogram<V, C, H>::add(const V&) [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’
tests/../histogram.hpp:57:60: instantiated from ‘pnw::histogram<V, C, H>::histogram(const V&, pnw::histogram<V, C, H>::TYPE_t) [with V = std::vector<unsigned char>, C = long unsigned int, H = std::unordered_map<unsigned char, long unsigned int, std::hash<unsigned char>, std::equal_to<unsigned char>, std::allocator<std::pair<const unsigned char, long unsigned int> > >]’
tests/t_histogram.cpp:38:61: instantiated from ‘void test_dense_histogram() [with T = unsigned char, C = long unsigned int]’
tests/t_histogram.cpp:64:5: instantiated from ‘void test_histograms() [with C = long unsigned int]’
tests/t_histogram.cpp:200:29: instantiated from here
/usr/include/c++/4.6/bits/stl_pair.h:156:2: error: assignment of read-only member ‘std::pair<const unsigned char, long unsigned int>::first’
make: *** [tests/t_histogram.o] Error 1
std::remove_if
不适用于std::unordered_map
吗?
【问题讨论】:
我也落入了这个陷阱,但现在想起来 std::remove(将元素移动到容器的末尾)无法与关联容器一起使用。 “容器的尽头”已经没有任何意义了。 【参考方案1】:答案是否定的(您不能在关联容器上使用remove_if
)。你需要做一个简单的循环; erase(iterator)
成员现在返回下一个有效的迭代器 - 所以你的循环变成:
for(auto it = begin(m_map); it != end(m_map);)
if (it->second == 0)
it = m_map.erase(it); // previously this was something like m_map.erase(it++);
else
++it;
【讨论】:
【参考方案2】:Stephan T. Lavavej 有a proposal of Uniform Container Erasure:
template <class K, class T, class H, class P, class A, class Predicate>
void erase_if(unordered_map<K, T, H, P, A>& c, Predicate pred);
即
std::erase_if(m_map, [](const Bin& bin) return bin.second == 0; );
不幸的是,它没有成为 C++17。我想这与 Ranges TS 的采用有关。
【讨论】:
以上是关于从满足谓词的无序映射中删除元素的主要内容,如果未能解决你的问题,请参考以下文章