查找矢量中具有相同值的所有元素,然后从矢量中擦除所有元素
Find all elements with the same value in a vector, then erase all of them out of the vector
问题是我需要在向量中找到所有具有相同值的元素,对它们执行某些操作,然后将它们全部从向量中删除。继续这样做,直到向量为空。
vector<unsigned> L;
vector<unsigned>::iterator it, it2, it3;
vector<unsigned> vec;
unsigned Z;
// populate the vector (1, 2, 3, 4, 2, 4)
for(unsigned i = 1; i <= 4; ++i)
L.push_back(i);
for(unsigned i = 2; i <= 4; i = i + 2)
L.push_back(i);
it = L.begin();
while(it != L.end() -1){
cout<< "*it = " << *it << endl;
Z=0;
vec.clear();
it2 = it + 1;
cout<< "*it2 = " << *it2 << endl;
while(it2 != L.end()){
cout << "Loop *it2 = " << *it2 <<endl;
if(*it == *it2){
vec.push_back(*it);
L.erase(it2); // iterator automatically points to the next element
cout<< "after erase(it2), *it2 = " << *it2 << endl;
continue;
}
++it2;
}
// do something (here I calculate the average)
for(it3 = vec.begin(); it3 != vec.end(); ++it3)
Z = Z+ *it3;
Z= Z/vec.size();
cout<< "Z = " << Z << endl << endl;
L.erase(it); // iterator automatically points to the next element
}
输出为:
*it = 1
*it2 = 2
Loop *it2 = 2
Loop *it2 = 3
Loop *it2 = 4
Loop *it2 = 2
Loop *it2 = 4
然后它停止工作
如果我用这段代码填充向量
// populate the vector (1, 2, 3, 4, 1, 3)
for(unsigned i = 1; i <= 4; ++i)
L.push_back(i);
for(unsigned i = 1; i <= 4; i = i + 2)
L.push_back(i);
然后输出为
*it = 1
*it2 = 2
Loop *it2 = 2
Loop *it2 = 3
Loop *it2 = 4
Loop *it2 = 1
after erase(it2), *it2 = 3
Loop *it2 = 3
Z = 1
*it = 2
*it2 = 3
Loop *it2 = 3
Loop *it2 = 4
Loop *it2 = 3
它在这里停止工作
我知道第二个while循环有问题,但我无法弄清楚它是什么。任何帮助将不胜感激。
如果目标是
- 处理重复项,然后
- 擦除它们
更简单的解决方案,那就是使用 std::stable_partition 以及一个std::set
:
#include <algorithm>
#include <vector>
#include <iterator>
#include <set>
#include <iostream>
#include <numeric>
using namespace std;
int main()
{
std::vector<int> L = { 1, 2, 4, 3, 2, 4 };
std::set<int> tempSet;
//...
// partition the elements, unique items on left, duplicates on right
auto divider = stable_partition(L.begin(), L.end(), [&](int n)
{
// return true if item is not in the set, false otherwise
return tempSet.insert(n).second;
});
// do something with the duplicates, for example, print them
cout << "Here are the dups:n";
copy(divider, L.end(), ostream_iterator<int>(cout, " "));
// get the average
// get number of duplicates
size_t numDups = std::distance(divider, L.end());
double avg = 0.0;
// compute average using std::accumulate
if ( numDups > 0 )
avg = std::accumulate(divider, L.end(), 0.0) / numDups;
cout << "nThe average of the duplicates is: " << avg << "n";
// erase the duplicates
L.erase(divider, L.end());
// print the updated vector now
cout << "nnHere is the resulting vector:n";
copy(L.begin(), L.end(), ostream_iterator<int>(cout, " "));
}
现场示例,C++ 14
这是相同的代码,但使用 C++ 03(对于那些没有 C++11/14 的人(:
现场示例,C++ 03
请注意,上面的代码中没有循环。 一切都由算法函数完成。 分区、平均计算、擦除等都是在没有循环的情况下执行的。
基本上,我们测试每个项目以查看该项目是否存在于集合中。 如果是这样,那么它将转到分区的右侧,如果没有,则该项目将转到分区的左侧。
返回值divider
是分区中作为"分界线"的元素的迭代器。 一旦项目被分区,那么我们就可以通过使用divider
告诉我们"好"项目在哪里以及"即将删除"项目在哪里来轻松处理它们。
顺便说一句,这是我第一次成功编译它时就起作用了——这种"运气"让它快速工作的一个主要原因是,当给定正确的参数时(并且如果谓词函数编写正确(,算法函数只是普通工作。 擦除容器中的项目、移动项目等,尤其是像矢量这样的序列容器,几乎总是使用 1、2 或 3 个算法函数来涵盖。
的解决方案,它的灵感来自PaulMcKenzie的代码(请不要介意我重用你的一些台词(。就像他一样,我没有使用任何手写循环,而是使用了STL的算法,人们应该始终首先考虑这一点。
在我的解决方案中,我只使用另一个完全相同类型的容器,并且只有两种简单的算法:std::remove_if
和std::find
。这样,代码使意图更加清晰:查找重复项并删除它们。另请注意,当拥有比int
更复杂的容器时,使用std::move
应该派上用场。在这种情况下,人们可能不得不考虑使用std::find_if
当然。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> L = { 1, 2, 4, 3, 2, 4 };
using cont = decltype(L);
using vt = cont::value_type;
// find duplicates and move them to separate container
cont D;
D.reserve(L.size());
D.swap(L);
D.erase(std::remove_if(D.begin(), D.end(), [&L] (vt& value)
{
if (L.cend() == std::find(L.cbegin(), L.cend(), value))
{
L.emplace_back(std::move(value));
return true;
}
return false;
}), D.end());
// do something with the duplicates, for example, print them
std::cout << "Here are the dups:n";
std::copy(D.cbegin(), D.cend(), std::ostream_iterator<vt>(std::cout, " "));
// print the vector now
std::cout << "nnHere is the resulting vector:n";
std::copy(L.begin(), L.end(), std::ostream_iterator<vt>(std::cout, " "));
return 0;
}
在这里看到它的实际效果。
问题出在您的erase
呼叫上。 erase
不会自动更新迭代器;它将迭代器返回到下一个元素。 要修复它,您需要使用
it2 = L.erase(it2);
及以后
it = L.erase(it);
vector<unsigned> L;
vector<unsigned>::iterator it, it2, it3;
vector<unsigned> vec;
unsigned Z;
// populate the vector (1, 2, 3, 4, 2, 4)
for(unsigned i = 1; i <= 4; ++i)
L.push_back(i);
for(unsigned i = 2; i <= 4; i = i + 2)
L.push_back(i);
std::set<unsigned int> myset;
for(it = L.begin(); it != L.end(); ++it){
myset.insert(*it);
}
for(std::set<unsigned int>::iterator iter = myset.begin();
iter != myset.end(); ++iter){
std::cout << "element = " << *iter << std::endl;
Z += *iter;
}
std::cout << "sum = " << Z << std::endl;
Z = Z/myset.size();
std::cout<< "Average value = " << Z << std::endl;
L.clear();
我终于找到了我自己问题的解决方案。问题是
- 我们有一个包含许多重复元素的向量
L
。 - 我们需要找到所有的 dup 元素
- 对 dup 元素执行某些操作
我的方法是在L
上使用 2 个迭代器,比如说 it
和 it2
。 it
保留在L
的开头,而it2
将穿过向量。如果*it
和*it2
具有相同的值,那么我们将*it2
放入临时向量vec
中。然后,我们L.erase(it2)
. it2
会一直移动到L
年底,将所有dup元素收集到vec
中,然后从L
中删除它们。当it2
到达L
末尾时,我们称之为L.erase(it)
。之后,该过程继续,直到向量L
为空。
这是我修改的代码。需要注意的最重要的事情是 while
中的状况 .我使用 while(it < L.end())
而不是 while(it != L.end())
因为当我们擦除元素时,迭代器会以某种方式将条件传递!=
.
我正在使用旧的编译器(早于 C++0x(,因为我现在不想弄乱环境。因此,任何人都可以安全地使用我的代码。
vector<unsigned> L;
vector<unsigned>::iterator it, it2, it3, it4;
vector<unsigned> vec; //temporary variable to store matched elements
float Z;
// populate the vector (1, 2, 3, 4, 1, 3)
for(unsigned i = 1; i <= 4; ++i)
L.push_back(i);
for(unsigned i = 1; i <= 4; i = i + 2)
L.push_back(i);
it = L.begin();
while(it < L.end()){
cout<< "*it = " << *it << endl;
Z=0;
vec.clear();
vec.push_back(*it);
if(L.size() == 1){
cout << "Last element of vector = " << *it <<endl;
goto Loop1;
}
else
it2 = it + 1;
while(it2 < L.end()){
cout << "Loop *it2 = " << *it2 <<endl; //debug
if(*it == *it2){
vec.push_back(*it2);
L.erase(it2); // iterator automatically points to the next element
cout<< "after erase(it2), *it2 = " << *it2 << endl; //debug
continue;
}
++it2;
}
Loop1:
for(it3 = vec.begin(); it3 != vec.end(); ++it3)
Z = Z+ *it3;
Z= Z/vec.size();
cout<< "Z = " << Z << endl ;
if(L.empty()) break;
L.erase(it); // iterator automatically points to the next element
//debug
cout<< endl << "new vector = ";
for(it4 = L.begin(); it4 != L.end(); ++it4)
cout << *it4 << ' ';
cout << endl;
}
@PaulMcKenzie:我花了一段时间才了解您在 C++14 中的写作风格以及我不熟悉的 STL 函数的使用。您的代码处于非常高的水平,对于初学者来说很难。无论如何,我选择它作为您贡献的最佳答案。我真的从你身上学到了很多东西。感谢您的快速回复。
- 擦除while循环中迭代的元素
- 擦除许多矢量元素,同时使用'auto'
- 擦除是否删除 stl 无序列图元素使用的堆内存
- 调用 erase() 函数是否也会在擦除元素之前更改迭代器值?
- 为什么在功能内擦除元素后不列出更新?
- 在任一方向上迭代容器并擦除元素
- 擦除矢量中的所有元素,直到第一个非零元素C++
- 迭代时擦除设置元素///
- 从向量和对向量中擦除元素的差异
- 如何安全地擦除 std::vector 中的元素
- 如何将某个元素从shared_ptr擦除到对象向量?
- 如何擦除矢量元素中没有特定字符的元素
- 矢量擦除范围内的元素
- 给定一个向量,擦除低于 itemsnum 的元素
- 从地图上擦除元素,然后将其放回原处
- 使用 str.erase() 的索引擦除字符串的元素?
- C 矢量元素擦除与新向量创建
- 迭代一组和擦除元素
- 使用常量键从集合中擦除元素
- 从向量中擦除元素是否也会擦除元素中存在的所有成员向量