问题描述
如何删除向量alphabets
中与字符串plaintext
中的任何字符匹配的元素?
这是我的尝试:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main()
{
//init
std::vector<std::string> alphabets{ "a","b","c","d","e","f","g","h","i","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z" };
//input
std::string plaintext;
std::cout << "enter plain text: ";
std::cin >> plaintext;
for (std::string::iterator it = plaintext.begin(); it != plaintext.end(); it++)
{
std::vector<std::string>::iterator toErase;
toErase = std::find(alphabets.begin(),alphabets.end(),*it);
if (toErase != alphabets.end())
{
alphabets.erase(toErase);
}
}
}
当我尝试编译它时。但是我遇到了这个错误:
17: note: 'std::__cxx11::basic_string<char>' is not derived from
'const std::istreambuf_iterator<_CharT,_Traits>' { return *__it == _M_value; }
...
203 : 5 : note : candidate : 'template<class _CharT,class _Traits> bool
std::operator==(const std::istreambuf_iterator<_CharT,_Traits>&,const
std::istreambuf_iterator<_CharT,_Traits>&)'
operator==(const istreambuf_iterator<_CharT,_Traits> & __a,...
解决方法
*it
的类型为char
,而不是std::string
。这就是编译器所抱怨的。因此,您需要按照以下方式将std::string
传递给std::find
。
auto toErase = std::find(alphabets.begin(),alphabets.end(),std::string{ *it });
// ^^^^^^^^^^^^^^^^^^
这里是a demo。
另外,请注意以下几点:
- 您可以将
std::vector<std::string> alphabets
更改为std::vector<char> alphabets
甚至一个std::string
作为您的alphabets
包含/表示char
为字符串。对于std::string
(即alphabets
),std::basic_string::find
更适合使用,而不是放在首位使用更一般的std::find
。 - 要进行矢量擦除,可以使用erase–remove
idiom,或者
从C ++ 20开始,使用
std::vector
本身的非成员函数,因此 叫std::erase_if
。
在
std::find(alphabets.begin(),*it);
alphabets.begin()
和alphabets.end()
是std::vector
迭代器中的std::string
,但是it
是std::string
迭代器,它对字符进行迭代,这些参数不兼容,如果没有某种转换,则不能在std::find
中一起使用。
那是纠正代码的更好方法,那就是将过于复杂的alphabets
容器从std::vector<std::string>
变成简单的std::string
。
//init
std::string alphabets{"abcdefghiklmnopqrstuvwxyz"}; //<--- simple string
//input
std::string plaintext;
std::cout << "enter plain text: ";
std::cin >> plaintext;
for (std::string::iterator it = plaintext.begin(); it != plaintext.end(); it++)
{
std::string::iterator toErase; //<--- string iterator
/*or auto */ toErase = std::find(alphabets.begin(),*it);
if (toErase != alphabets.end())
{
alphabets.erase(toErase);
}
}
,
这是我的理解:
您有一个说str1
的字符串。现在,您又得到了另一个字符串,str2
。现在,您要删除str1
中存在的str2
中的所有字符。
在这种情况下,我建议将输入扫描为字符串而不是向量,然后使用delete
循环
for(auto it = str1.begin(); it != str1.end(); it++) {
if(str2.find(std::string{*it}) != std::string::npos) {
it = str1.erase(it);
}
}
,
C ++ 20 oneliner解决方案。
它更多地关注您想要做什么 (它使用std::erase_if
是因为我们要根据条件擦除元素,并且它使用std::find
来检查该条件),而不是怎么做(实际上没有for
循环。
#include <string>
#include <vector>
#include <iostream>
int main() {
// inputs
// I don't like this alphabet; a std::vector<char> would have been much better
// and it would allow to remove the ugly [0] in the std::find below
std::vector<std::string> alphabet{"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"};
std::string plaintext{"abcdefghijklmnopq"};
// the solution is a oneliner
std::erase_if(alphabet,[&plaintext](auto x){
return !(std::find(std::begin(plaintext),std::end(plaintext),x[0]) == std::end(plaintext));
});
// output to verify the correct result
for (auto& e : alphabet) { // prints r s t u v w x y z
std::cout << e << ' ';
}
}