簡體   English   中英

如何從具有特定值的 stl 向量中刪除項目?

[英]How do I remove an item from a stl vector with a certain value?

我正在查看 stl 矢量的 API 文檔,並注意到矢量類上沒有允許刪除具有特定值的元素的方法。 這似乎是一種常見的操作,而且沒有內置的方法來做到這一點似乎很奇怪。

std::remove實際上並不從容器中刪除元素:它將要刪除的元素移動到容器的末尾,並返回新的結束迭代器,該迭代器可以傳遞給container_type::erase以實際刪除額外的元素現在位於容器末尾的元素:

std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());

如果你想刪除一個項目,下面會更有效率。

std::vector<int> v;


auto it = std::find(v.begin(), v.end(), 5);
if(it != v.end())
    v.erase(it);

或者,如果訂單對您無關緊要,您可以避免移動物品的開銷:

std::vector<int> v;

auto it = std::find(v.begin(), v.end(), 5);

if (it != v.end()) {
  using std::swap;

  // swap the one to be removed with the last element
  // and remove the item at the end of the container
  // to prevent moving all items after '5' by one
  swap(*it, v.back());
  v.pop_back();
}

使用帶有 begin 和 end 迭代器的全局方法 std::remove,然后使用 std::vector.erase 實際刪除元素。

文檔鏈接
std::remove http://www.cppreference.com/cppalgorithm/remove.html
std::vector.erase http://www.cppreference.com/cppvector/erase.html

std::vector<int> v;
v.push_back(1);
v.push_back(2);

//Vector should contain the elements 1, 2

//Find new end iterator
std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);

//Erase the "removed" elements.
v.erase(newEnd, v.end());

//Vector should now only contain 2

感謝 Jim Buck 指出我的錯誤。

c++20開始:

一個非成員函數引入了std::erase ,它將要刪除的向量和值作為輸入。

前任:

std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);

如果你有一個未排序的向量,那么你可以簡單地與最后一個向量元素交換,然后resize()

使用有序容器,最好使用std::vector::erase() 請注意,在<algorithm>中定義了一個std::remove() ,但這實際上並沒有進行擦除。 (仔細閱讀文檔)。

其他答案涵蓋了如何做好這一點,但我想我還想指出,這不在向量 API 中並不奇怪:它是低效的,通過向量線性搜索值,然后是一堆復制以將其刪除。

如果您正在密集地執行此操作,則可能值得考慮 std::set 出於這個原因。

*

C++ 社區已經聽到了您的請求 :)

*

C++ 20現在提供了一種簡單的方法。 它變得如此簡單:

#include <vector>
...
vector<int> cnt{5, 0, 2, 8, 0, 7};
std::erase(cnt, 0);

您應該檢查std::erasestd::erase_if

它不僅會刪除值的所有元素(此處為“0”),而且會以O(n)的時間復雜度進行。 這是你能得到的最好的。

如果你的編譯器不支持 C++ 20,你應該使用erase-remove idiom

#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());

另請參閱std::remove_if以能夠使用謂詞...

這是上面鏈接中的示例:

vector<int> V;
V.push_back(1);
V.push_back(4);
V.push_back(2);
V.push_back(8);
V.push_back(5);
V.push_back(7);

copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
    // The output is "1 4 2 8 5 7"

vector<int>::iterator new_end = 
    remove_if(V.begin(), V.end(), 
              compose1(bind2nd(equal_to<int>(), 0),
                       bind2nd(modulus<int>(), 2)));
V.erase(new_end, V.end()); [1]

copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
    // The output is "1 5 7".

一個更短的解決方案(不會強迫您重復向量名稱 4 次)是使用 Boost:

#include <boost/range/algorithm_ext/erase.hpp>

// ...

boost::remove_erase(vec, int_to_remove);

請參閱http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.html

有兩種方法可以用來特別擦除一個項目。 讓我們拿一個向量

std :: vector < int > v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(40);
v.push_back(50);

1)非有效方式:雖然它看起來很有效,但這並不是因為擦除函數刪除元素並將所有元素向左移動1。所以它的復雜度將是O(n ^ 2)

std :: vector < int > :: iterator itr = v.begin();
int value = 40;
while ( itr != v.end() )
{
   if(*itr == value)
   { 
      v.erase(itr);
   }
   else
       ++itr;
}

2)高效方式(推薦) :也稱為ERASE-REMOVE成語

  • std::remove 將給定范圍轉換為一個范圍,其中所有比較不等於給定元素的元素都移動到容器的開頭。
  • 所以,實際上不要刪除匹配的元素。 它只是將不匹配的內容轉移到開始並將迭代器提供給新的有效結束。 它只需要 O(n) 復雜度。

刪除算法的輸出是:

10 20 30 50 40 50 

因為 remove 的返回類型是指向該范圍新端的迭代器。

template <class ForwardIterator, class T>
  ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);

現在使用向量的擦除功能從向量的新端到舊端刪除元素。 它需要 O(1) 時間。

v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );

所以這個方法在 O(n) 中工作

擦除刪除習語類似,對於vector ,可以使用resizeremove並使用迭代器距離計算:

std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.resize(std::remove(vec.begin(), vec.end(), int_to_remove) - vec.begin());

在這里測試。

如果您想在沒有任何額外內容的情況下執行此操作,則包括:

vector<IComponent*> myComponents; //assume it has items in it already.
void RemoveComponent(IComponent* componentToRemove)
{
    IComponent* juggler;

    if (componentToRemove != NULL)
    {
        for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
        {
            if (componentToRemove == myComponents[currComponentIndex])
            {
                //Since we don't care about order, swap with the last element, then delete it.
                juggler = myComponents[currComponentIndex];
                myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
                myComponents[myComponents.size() - 1] = juggler;

                //Remove it from memory and let the vector know too.
                myComponents.pop_back();
                delete juggler;
            }
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM