如何从STL容器中删除元素?

时间:2013-04-15 11:03:14

标签: c++ c++11 stl std

如何从STL容器中删除元素,具有指定的,或满足某些条件

对于不同种类的容器,是否有单一的通用或统一的方法?

1 个答案:

答案 0 :(得分:54)

不幸的是,没有一个统一接口或模式可以从STL容器中删除元素。 但是出现了三种行为:

std :: vector Pattern

要从 std::vector 中删除满足特定条件的元素,常用的技术就是所谓的erase-remove idiom

如果vstd::vector的实例,并且我们想要从向量中删除值为x的元素,则可以使用以下代码:

// Erase elements having value "x" from vector "v"
v.erase( std::remove(v.begin(), v.end(), x), v.end() );

如果擦除元素要满足的标准比要擦除的简单“元素更复杂== x”,则可以使用std::remove_if()算法代替{{1 }}:

std::remove()

其中// Erase elements matching "erasing_condition" from vector "v" v.erase( std::remove_if(v.begin(), v.end(), erasing_condition), v.end() ); 是一元谓词,可以用几种形式表示:例如它可以是 erasing_condition - 返回函数将vector元素类型作为输入(因此,如果返回的值为bool,则元素将从向量中删除;如果是{ {1}},它不会);或者可以将 in-line 表示为 lambda ;它可以是functor;等

truefalse都是来自std::remove()标头的通用算法。)

以下是明确的解释from Wikipedia

  

std::remove_if()库提供<algorithm>algorithm   算法。因为这些算法在一系列范围内运行   由两个前向迭代器表示的元素,他们不知道   底层容器或集合。因此,实际上没有元素   从容器中取出。相反,所有不适合的元素   删除标准汇集到范围的前面,在   相同的相对顺序。其余元素保留为有效,但是   未指明的状态。完成此操作后,remove将返回一个迭代器   指出一个经过最后一个未被删除的元素。

     

要实际消除容器中的元素,remove_if会合并   使用容器的remove成员函数,因此得名   “擦除 - 删除成语”。

基本上,removeerase会压缩满足范围前面的删除条件的元素(即{{1}的开头) }),然后std::remove()实际上从容器中删除了剩余的元素。

此模式也适用于 std::remove_if() 等其他容器。

std :: list Pattern

要清除 vector 中的元素,可以使用简单的 erase()std::deque方法

std::list

(其中remove()是一元谓词,在上一节中针对remove_if()讨论了相同的特征。)

相同的模式可以应用于类似的容器,例如 // Erase elements having value "x" from list "l" l.remove( x ) // Erase elements satisfying "erasing_condition" from list "l" l.remove_if( erasing_condition );

关联容器(例如std :: map,std :: set,...)Pattern

关联容器,例如 erasing_condition std::remove_if() std::forward_list 等,遵循此处描述的常见模式:

  1. 如果擦除条件是简单的键匹配(即“擦除元素 使用键x“),可以调用一个简单的 std::map方法

    std::set
  2. 如果擦除条件更复杂,并且由某些自定义表示 一元谓词(例如“擦除所有奇数元素”),然后可以使用std::unordered_map循环 (在循环体中检查明确的擦除条件,并调用erase()方法):

    // Erase element having key "k" from map "m":
    m.erase( k );
    
  3. 统一方法的必要性

    从上述分析可以看出,遗憾的是,没有一种统一的通用方法可以从STL容器中删除元素。

    下表总结了上述模式:

    for

    根据特定容器编写不同的特定代码容易出错,难以维护,难以阅读等。

    但是,可以为不同的容器类型编写具有通用名称的函数模板(例如erase(iterator)// // Erase all elements from associative container "c", satisfying "erasing_condition": // for (auto it = c.begin(); it != c.end(); /* "it" updated inside loop body */ ) { if ( erasing_condition(*it) ) { // Erase the element matching the specified condition // from the associative container. it = c.erase(it); // Note: // erase() returns an iterator to the element // that follows the last element removed, // so we can continue the "for" loop iteration from that position. } else { // Current element does _not_ satisfy erasing condition, // so we can just move on to the next element. ++it; } } 重载,并将上述模式实现嵌入到这些函数中。
    因此,客户端可以简单地调用那些----------------+------------------------------------------ Container | Erasing Pattern ----------------+------------------------------------------ | vector | Use erase-remove idiom. deque | | ----------------+------------------------------------------ | list | Call remove()/remove_if() methods. forward_list | | ----------------+------------------------------------------ | map | Simple erase(key) method call, set | or unordered_map | loop through the container, multimap | and call erase(iterator) on matching | condition. ... | | ----------------+------------------------------------------ erase()泛型函数,编译器将根据容器类型将调用分派给正确的实现(在编译时)。

    使用模板元编程技术的更优雅的方法是by Stephan T. Lavavej here