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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:20:47  来源:igfitidea点击:

remove_if equivalent for std::map

c++stlmap

提问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_ifbut 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_ifis 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 iteris 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 ContainerTitems 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++求值时,迭代器的++运算符将返回当前项并指向调用后的下一项。