【问题标题】:Modify strings within a vector? (Without using loops)修改向量中的字符串? (不使用循环)
【发布时间】:2020-09-12 18:40:12
【问题描述】:

我正在尝试获取字符串向量并删除每个不是字母的字符(数字、符号等)。我也没有尝试使用循环。

下面是一个向量的例子:

std::vector<std::string> a = {"he2llo*", "3worl$d"};

我希望返回的字符串如下所示:

std::vector<std::string> a = {"hello", "world"};

现在我正在尝试使用转换和擦除算法,但我无法正确使用语法。

这显然是不完整的,但这是我目前所拥有的基本设置:

int trim(std::vector<std::string> a){
    std::transform(a.begin(), a.end(), a.erase())

【问题讨论】:

  • 需要指定transform的输出范围。此外,您可以编写一个 lambda,从字符串中删除非字母。
  • 确实意识到使用begin()end() 的所有内容几乎肯定会在幕后循环,是吗?除了短的源代码,我不确定通过避免显式循环你会获得什么。
  • @paxdiablo 人们可能会争辩说它更清楚地传达了意图。
  • 我猜也可以使用递归..
  • 我不允许为此使用循环。我想写 lambda 是我遇到的麻烦。

标签: c++ algorithm vector stl iterator


【解决方案1】:

您可以使用 STL &lt;algorithm&gt;s 以不同的方式尝试它,我实现了一个仿函数来处理每个单词:

#include <iostream>
#include <vector>
#include <cctype>
#include <algorithm>

class Processing{

public:

    std::string operator()(std::string& value){

        for_each(value.begin(), value.end(), [&](char v) mutable throw() ->
                 void {
                    auto fetch = std::find_if( value.begin(), value.end(), [&](char v)mutable throw()->
                                              bool{
                                                  return(!isalpha(v));
                                                  });
                    if(*fetch){
                        value.erase( fetch );
                    }
                 });
        return value;
    }

};

int main()
{

  std::vector<std::string> values = {"44h%ello333","%w%or333ld21"};

  std::for_each(values.begin(),values.end(), Processing());

  std::for_each(values.begin(),values.end(), [](std::string& value)->
                void {
                    std::cout<<value<<" ";
                    });

    return 0;
}

【讨论】:

    【解决方案2】:

    你可以使用 C++20 std::erase_if

    #include<string>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    
    int main() {
      std::vector<std::string> a = {"he2llo*", "3worl$d"};
      std::transform(a.begin(), a.end(), a.begin(), 
        [](auto& str) { 
          std::erase_if(str, [](const auto& chr){return !isalpha(chr);}); 
          return std::move(str);
          });
      for (const auto& str: a){
        std::cout << str << std::endl;
      }
    }
    

    【讨论】:

      【解决方案3】:

      这是使用 algorithm 标头和 lambda 函数的一种方法:

      #include <iostream>
      #include <vector>
      #include <string>
      #include <algorithm>
      
      int main() {
          std::vector<std::string> strArr = {"he2llo*", "3worl$d"};
          std::transform(strArr.begin(), strArr.end(), strArr.begin(), [](std::string &str) -> std::string {
              str.erase(std::remove_if(str.begin(), str.end(), [](char chr) -> bool {
                  return ! isalpha(chr);
              }), str.end());
              return str;
          });
      
          std::for_each(strArr.begin(), strArr.end(), [](const auto &str) {
              std::cout << str << '\n';
          });
      
          return 0;
      }
      

      外部 lambda 处理每个字符串以使用 remove_if 擦除特定字符,而内部 lambda 仅控制 哪些 个字符被删除。这是否比基于循环的解决方案更具可读性还有待商榷:-)

      【讨论】:

      • 将 lambda 从转换中移出并命名,可能有助于提高可读性。当然仍然是主观的,但只是一个想法。
      【解决方案4】:

      递归..

      #include <iostream>
      #include <vector>
      
      std::string remove_bad_characters(std::string input, std::string result)
      {
          if (input.size() == 0)
          {
              return result;
          }
      
          if (!isalpha(input[0]))
          {
              return remove_bad_characters(input.substr(1), result);
          }
      
          result += input[0];
          return remove_bad_characters(input.substr(1), result);
      }
      
      std::vector<std::string> edit_bad_strings(std::vector<std::string> input, std::size_t index)
      {
          if (index == input.size())
          {
              return input;
          }
      
          input[index] = remove_bad_characters(input[index], "");
          return edit_bad_strings(input, index + 1);
      }
      
      
      int main() {
      
          std::cout<<remove_bad_characters("h!ello!", "")<<"\n";
          std::vector<std::string> good = edit_bad_strings(std::vector<std::string>{"h!ell@o", "wo0rl-d"}, 0);
      
          for (std::string str : good)
          {
              std::cout<<str<<" ";
          }
      
          return 0;
      }
      

      【讨论】:

        【解决方案5】:

        可以在向量上使用std::for_each,然后在字符串上使用erase-remove idiom,如下

        #include <vector>
        #include <string>
        #include <algorithm>
        #include <iostream>
        
        int main() {
            std::vector<std::string> a = {"he2llo*", "3worl$d"};
            std::for_each(a.begin(), a.end(),[](auto & str){
                str.erase(std::remove_if(str.begin(), str.end(), [] (auto & character){return !isalpha(character);}), str.end());
            });
        
            for(auto const & el : a)
                std::cout << el << " ";
        
        }
        The output:
        hello world 
        

        【讨论】:

        • 可能没有理由将character 作为参考传递,因为您没有更改它。而且,如果我是一个聪明的教育者,我会用for而不是另一个for_each来做输出循环:-)但这比转换简单一点,所以对此表示赞赏.
        【解决方案6】:

        您可以使用std::for_each 代替循环来遍历每个元素。 然后你可以在向量的每个元素上应用std::transform

        你可以参考-

        http://www.cplusplus.com/reference/algorithm/for_each/ http://www.cplusplus.com/reference/algorithm/transform/

        【讨论】:

        • 你为什么不展示一个可以解决问题的实际sn-p代码?
        • “您可以使用 std::for_each 代替循环” - std::for_each 内部循环。
        猜你喜欢
        • 2020-07-26
        • 1970-01-01
        • 1970-01-01
        • 2018-03-17
        • 2015-09-19
        • 2016-06-01
        • 2013-01-08
        • 1970-01-01
        • 2020-05-10
        相关资源
        最近更新 更多