我的vector<Suggestions> finalSuggestions
包含string
word
和一些int
num
。
如果这个单词满足某些条件,我想将该对象移动到向量的前面,将其从任何地方移除。
我可以使用vector::insert
for (auto &x: finalSuggestions) {
if ( double((x.num)/(topword.num)) < 50)
{
finalSuggestions.insert(finalSuggestions.begin(),x);
break;
}
}
但我不知道如何将其从列表中的位置删除。
例如,对于某些任意向量{ 1,2,3,4,50,6,7,8,9 }
,
如果50符合条件,请将其移至列表的前面并将其从原处删除,然后返回{ 50,1,2,3,4,6,7,8,9 }
。上面的代码返回{ 50,1,2,3,4,50,6,7,8,9 }
我正在调查vector::erase
,但我遇到了问题,并且花费的时间超过了应有的时间。
我设想了一个简单的解决方案(但这显然不起作用)
for (auto &x: finalSuggestions) {
if ( double((x.num)/(topword.num)) < 50)
{
finalSuggestions.insert(finalSuggestions.begin(),x);
finalSuggestions.erase(x);
break;
}
}
我读了擦除删除习语(这是我的实现):
finalSuggestions.erase( remove( begin(finalSuggestions), end(finalSuggestions), x ), end(finalSuggestions) );
但是我收到了一个我不明白的错误:
In instantiation of '_FIter std::remove(_FIter, _FIter, const _Tp&) [with _FIter = __gnu_cxx::__normal_iterator<Suggestion*, std::vector<Suggestion> >; _Tp = Suggestion]':|
答案 0 :(得分:19)
使用std::rotate
。它比删除和重新插入要快很多。
例如:
for (auto it = finalSuggestions.begin(), lim = finalSuggestions.end();
it != lim;
++it) {
if (it->num < 50 * topword.num) {
std::rotate(finalSuggestions.begin(), it, it + 1);
break;
}
}
更好的是,正如@JerryCoffin在评论中建议的那样,使用std::find_if
来找到支点:
auto pivot = std::find_if(finalSuggestions.begin(),
finalSuggestions.end(),
[&topword](const Suggestions& s) -> bool {
return s.num < 50 * topword.num;
});
if (pivot != finalSuggestions.end()) {
std::rotate(finalSuggestions.begin(), pivot, pivot + 1);
}
答案 1 :(得分:8)
对于vector::erase
,您需要一个迭代器,因此不能使用基于范围的for
。请改用简单的for
循环。首先擦除一个元素,然后插入它,因为insert
使迭代器无效:
for (auto it = finalSuggestions.begin(); it != finalSuggestions.end(); ++it) {
if (some_condition(*it)) {
auto x = *it; // or std::move(*it)
finalSuggestions.erase(it);
finalSuggestions.insert(finalSuggestions.begin(), x /* or std::move(x) */);
break;
}
}
使用std::move
将允许您移动元素而不是复制它,这可以节省一些周期。
答案 2 :(得分:2)
您的迭代器使得很难知道相关元素的位置。您可能想尝试使用允许访问该位置的标准for
迭代器(由std::vector::erase
使用)
int len=finalSuggestions.size();
for (int i=0, ; i<len; ++i) {
// Save a copy of the item
auto item = finalSuggestions.at(i);
if (double((item.num)/(topword.num)) < 50) {
// Erase the item in the list
finalSuggestions.erase(i);
// Add the copy of the item back in at the front
finalSuggestions.insert(finalSuggestions.begin(), item);
break;
}
}
...或使用std :: iterator ...
for (auto it = finalSuggestions.begin(); it != finalSuggestions.end(); ++it) {
if (double((*it->num)/(topword.num)) < 50) {
// Save a copy of the item
auto item = *it;
// Erase the item in the list
finalSuggestions.erase(it);
// Add the copy of the item back in at the front
finalSuggestions.insert(finalSuggestions.begin(), item);
break;
}
}
std::vector
个对象对其元素使用连续内存,这意味着在更改容器期间实际移动内存。如果您要移动元素,可能需要查看std::list
或std:deque
。这些容器的定义几乎完全相同(读取:替换掉),使得替换它们非常简单。
<强>建议:强>
std::deque
设计用于在容器的开头和结尾进行最佳插入。取自网站cplusplus.com:
...它们提供类似于向量的功能,但是在序列的开头也有效地插入和删除元素,而不仅仅是在它的结尾。但是,与矢量不同,deques不能保证将其所有元素存储在连续的存储位置:...
答案 3 :(得分:1)
安东的回答是正确的。但是,如果你做了很多这样的事情,你应该考虑不同的数据结构。 erase
和insert
都是O(N)操作,其中N是vector
的大小。如果这是一个常见的操作,列表会更好。
答案 4 :(得分:1)
它在功能上等同于Anton的答案,但是我会使用std::find_if
来获取你正在寻找的元素的迭代器而不是循环。
//add #include <algorithm> to your source file
auto result = std::find_if(finalSuggestions.begin(), finalSuggestions.end(), condition_func);
if(result != finalSuggestions.end())
{
auto resultValue = *result;
finalSuggestions.erase(result);
finalSuggestions.insert(finalSuggestions.begin(), resultValue);
}
condition_func
应该是一个返回bool的函数,它接受一个与向量中元素类型匹配的参数(在本例中为Suggestion
):
bool condition_func(Suggestion elementValue) { /*condition here*/ }
有关find_if
的更多信息,请here。
答案 5 :(得分:0)
也许使用std :: iter_swap可以解决您的问题。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main () {
vector<int> myvector{};
for(int io{}; io<7; ++io) myvector.push_back(io+1);
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
cout << ' ' << *it;
cout << '\n';
iter_swap(myvector.begin(),myvector.begin()+2);//exchange the third element with the first.
cout << "myvector contains:";
for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}