C++ remove_if 等效于 std::map
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/800955/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
remove_if equivalent for std::map
提问by aJ.
I was trying to erase a range of elements from map based on particular condition. How do I do it using STL algorithms?
我试图根据特定条件从地图中删除一系列元素。我如何使用 STL 算法做到这一点?
Initially I thought of using remove_if
but it is not possible as remove_if does not work for associative container.
最初我想使用remove_if
但这是不可能的,因为 remove_if 不适用于关联容器。
Is there any "remove_if" equivalent algorithm which works for map ?
是否有任何适用于 map 的“remove_if”等效算法?
As a simple option, I thought of looping through the map and erase. But is looping through the map and erasing a safe option?(as iterators get invalid after erase)
作为一个简单的选择,我想到了遍历地图并擦除。但是循环遍历地图并擦除安全选项吗?(因为迭代器在擦除后无效)
I used following example:
我使用了以下示例:
bool predicate(const std::pair<int,std::string>& x)
{
return x.first > 2;
}
int main(void)
{
std::map<int, std::string> aMap;
aMap[2] = "two";
aMap[3] = "three";
aMap[4] = "four";
aMap[5] = "five";
aMap[6] = "six";
// does not work, an error
// std::remove_if(aMap.begin(), aMap.end(), predicate);
std::map<int, std::string>::iterator iter = aMap.begin();
std::map<int, std::string>::iterator endIter = aMap.end();
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
return 0;
}
采纳答案by Steve Folly
Almost.
几乎。
for(; iter != endIter; ) {
if (Some Condition) {
iter = aMap.erase(iter);
} else {
++iter;
}
}
What you had originally would increment the iterator twiceif you did erase an element from it; you could potentially skip over elements that needed to be erased.
如果您确实从中删除了一个元素,那么您最初拥有的会增加迭代器两次;您可能会跳过需要擦除的元素。
This is a common algorithm I've seen used and documented in many places.
这是我在许多地方看到使用和记录的常用算法。
[EDIT] You are correct that iterators are invalidated after an erase, but only iterators referencing the element that is erased, other iterators are still valid. Hence using iter++
in the erase()
call.
[编辑]您是正确的,迭代器在擦除后无效,但只有引用被擦除元素的迭代器,其他迭代器仍然有效。因此iter++
在erase()
通话中使用。
回答by Iron Savior
erase_if for std::map (and other containers)
对于 std::map(和其他容器)的擦除_if
I use the following template for this very thing.
我使用以下模板来做这件事。
namespace stuff {
template< typename ContainerT, typename PredicateT >
void erase_if( ContainerT& items, const PredicateT& predicate ) {
for( auto it = items.begin(); it != items.end(); ) {
if( predicate(*it) ) it = items.erase(it);
else ++it;
}
}
}
This won't return anything, but it will remove the items from the std::map.
这不会返回任何内容,但会从 std::map 中删除项目。
Usage example:
用法示例:
// 'container' could be a std::map
// 'item_type' is what you might store in your container
using stuff::erase_if;
erase_if(container, []( item_type& item ) {
return /* insert appropriate test */;
});
Second example (allows you to pass in a test value):
第二个示例(允许您传入测试值):
// 'test_value' is value that you might inject into your predicate.
// 'property' is just used to provide a stand-in test
using stuff::erase_if;
int test_value = 4; // or use whatever appropriate type and value
erase_if(container, [&test_value]( item_type& item ) {
return item.property < test_value; // or whatever appropriate test
});
回答by user1633272
Now, std::experimental::erase_if
is available in header <experimental/map>
.
现在,std::experimental::erase_if
在 header 中可用<experimental/map>
。
See: http://en.cppreference.com/w/cpp/experimental/map/erase_if
请参阅:http: //en.cppreference.com/w/cpp/experimental/map/erase_if
回答by 1800 INFORMATION
I got this documentation from the excellent SGI STL reference:
我从优秀的 SGI STL 参考资料中得到了这个文档:
Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.
Map 有一个重要的特性,即向 Map 中插入新元素不会使指向现有元素的迭代器失效。从映射中擦除元素也不会使任何迭代器失效,当然,实际上指向被擦除元素的迭代器除外。
So, the iterator you have which is pointing at the element to be erased will of course be invalidated. Do something like this:
因此,您拥有的指向要擦除的元素的迭代器当然会失效。做这样的事情:
if (some condition)
{
iterator here=iter++;
aMap.erase(here)
}
回答by partha biswas
The original code has only one issue:
原始代码只有一个问题:
for(; iter != endIter; ++iter)
{
if(Some Condition)
{
// is it safe ?
aMap.erase(iter++);
}
}
Here the iter
is incremented once in the for loop and another time in erase, which will probably end up in some infinite loop.
这里iter
在 for 循环中增加一次,在擦除中再增加一次,这可能会在某个无限循环中结束。
回答by Mandrake Root
Here is some elegant solution.
这是一些优雅的解决方案。
for (auto it = map.begin(); it != map.end();)
{
(SomeCondition) ? map.erase(it++) : (++it);
}
回答by piotr
From the bottom notes of:
从底部注释:
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
http://www.sgi.com/tech/stl/PairAssociativeContainer.html
a Pair Associative Container cannot provide mutable iterators (as defined in the Trivial Iterator requirements), because the value type of a mutable iterator must be Assignable, and pair is not Assignable. However, a Pair Associative Container can provide iterators that are not completely constant: iterators such that the expression (*i).second = d is valid.
Pair Associative Container 不能提供可变迭代器(在 Trivial Iterator 要求中定义),因为可变迭代器的值类型必须是 Assignable,而 pair 不是 Assignable。然而,一对关联容器可以提供不完全恒定的迭代器:这样的迭代器 (*i).second = d 是有效的。
回答by user109134
IMHO there is no remove_if()
equivalent.
You can't reorder a map.
So remove_if()
can not put your pairs of interest at the end on which you can call erase()
.
恕我直言,没有remove_if()
等价物。
您无法重新排序地图。
所以remove_if()
不能把你的兴趣放在你可以调用的末尾erase()
。
回答by Greg Domjan
Based on Iron Savior's answerFor those that would like to provide a range more along the lines of std functional taking iterators.
基于Iron Savior 的回答对于那些希望提供更多类似于 std 函数式迭代器的范围的人。
template< typename ContainerT, class FwdIt, class Pr >
void erase_if(ContainerT& items, FwdIt it, FwdIt Last, Pr Pred) {
for (; it != Last; ) {
if (Pred(*it)) it = items.erase(it);
else ++it;
}
}
Curious if there is some way to lose the ContainerT
items and get that from the iterator.
好奇是否有某种方法可以丢失ContainerT
项目并从迭代器中获取它。
回答by Vincent
First
第一的
Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.
Map 有一个重要的特性,即向 Map 中插入新元素不会使指向现有元素的迭代器失效。从映射中擦除元素也不会使任何迭代器失效,当然,实际上指向被擦除元素的迭代器除外。
Second, the following code is good
二、下面的代码不错
for(; iter != endIter; )
{
if(Some Condition)
{
aMap.erase(iter++);
}
else
{
++iter;
}
}
When calling a function, the parameters are evaluated before the call to that function.
调用函数时,会在调用该函数之前评估参数。
So when iter++ is evaluated before the call to erase, the ++ operator of the iterator will return the current item and will point to the next item after the call.
所以当在调用erase之前对iter++求值时,迭代器的++运算符将返回当前项并指向调用后的下一项。