【问题标题】:Delete elements in a std::vector<std::string> which matches with the characters in another given std::string删除 std::vector<std::string> 中与另一个给定 std::string 中的字符匹配的元素
【发布时间】:2020-12-19 07:20:00
【问题描述】:

如何删除向量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,
      ...

【问题讨论】:

  • 因为第二个字符串(字母)是固定的,我以后需要它来构造一个矩阵形式,如果它是一个向量会更容易
  • 单个字符(如'a')与只有一个字符的字符串(如"a")不同。你无法比较它们。
  • 稍后我需要将其转换为 2d 矢量,我需要在其中进行一些转置操作,所以我只是认为矢量会很容易操作。顺便说一句,谢谢,我会尝试使用字符串。
  • 即使已经回答了,我还是将此问题标记为需要澄清,因为问题的标题和正文描述了两种完全不同的意图。
  • @BalaGanesh,我做了更多的更改,但是问题仍然可以改进;例如,由于问题与 IO 无关,您可以删除 //input 部分并只输入 std::string plaintext{"abcdefghijklmnopqrst"};,因此您可以告诉您希望修改后的 alphabets 仅包含 {"u","v","w","x","y","z"}

标签: c++ algorithm stdvector stdstring c++-standard-library


【解决方案1】:

std::find(alphabets.begin(), alphabets.end(), *it);

alphabets.begin()alphabets.end()std::vectorstd::strings 迭代器,但 itstd::string 迭代器,它迭代字符,这些参数不兼容,不能一起使用std::find 没有某种转换。

也就是说,更正代码的更好方法是将过于复杂的 alphabets 容器从 std::vector&lt;std::string&gt; 转换为简单的 std::string

Live demo

//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(), alphabets.end(), *it);
    if (toErase != alphabets.end())
    {
        alphabets.erase(toErase);
    }
}

【讨论】:

    【解决方案2】:

    *it 的类型是 char 而不是 std::string。这就是编译器抱怨的地方。因此,您需要将std::string 传递给std::find,如下所示。

    auto toErase = std::find(alphabets.begin(), alphabets.end(), std::string{ *it });
     //                                                          ^^^^^^^^^^^^^^^^^^
    

    这里是a demo


    另外,请注意以下几点:

    • 您可以将std::vector&lt;std::string&gt; alphabets 更改为 std::vector&lt;char&gt; alphabets 甚至单个 std::string 作为您的 alphabets contains/ 将chars 表示为字符串。对于std::strings(即alphabets),std::basic_string::find 更适合使用,而不是首先使用更通用的std::find
    • 对于矢量擦除,您可以使用erase–remove idiom,或者 从 C++20 开始,使用 std::vector 本身的非成员函数,所以 叫 std::erase_if

    【讨论】:

      【解决方案3】:

      一个 C++20 oneliner 解决方案。

      它更关注 what 你想要做什么(它使用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 << ' ';
          }
      }
      

      【讨论】:

      • 是的,关于 lambda 的建议很有用,因为 lambda 是立即使用的,所以没有需要关心的生命周期问题,我会稍后提出。
      【解决方案4】:

      这是我的理解:
      你有一个字符串说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);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2022-10-24
        • 2011-09-17
        • 2011-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-25
        • 2019-11-07
        • 1970-01-01
        相关资源
        最近更新 更多