【问题标题】:Given a vector, erase elements lower than itemsnum [duplicate]给定一个向量,擦除低于 itemsnum 的元素 [重复]
【发布时间】:2017-12-06 03:37:47
【问题描述】:

这是我从字符串“results”向量中删除所有元素的函数,这些字符串没有“itemsnum”那么长。但是我有点担心它会多次调用自己,有没有更简单的方法?

vector<string> eraselower(vector<string> results, int itemsnum){ //erases all elements in vector which are not long enough
    for (unsigned j=0; j<results.size(); j++){
        if(results[j].length()<itemsnum ){ results.erase(results.begin()+j); }}
    for (unsigned j=0; j<results.size(); j++){
        if(results[j].length()<itemsnum ){ results=eraselower(results,itemsnum);}}
    return results;
}

谢谢。

【问题讨论】:

    标签: c++ vector


    【解决方案1】:

    最好的方法是erase-remove成语:

    #include <algorithm>
    #include <string>
    #include <vector>
    
    std::vector<std::string> eraselower(std::vector<std::string> results, int itemsnum)
    {
        results.erase(
            std::remove_if(results.begin(), results.end(),
                          [itemsnum](const std::string & s) {
                              return s.size() < itemsnum; }),
            results.end());
        return results;
    }
    

    【讨论】:

    • 您在 lambda 正文中忘记了 s.length()
    • @aschepler:谢谢,已修复!
    • 应该是std::remove_if,你传递的是谓词而不是值。
    • @Blastfurnace:是的,确实,谢谢。今天不是个好日子。
    • @Boris:我想问题是你的实际实施中的错误是否更容易发现:-)
    【解决方案2】:

    您的主要问题在于第一个 for 循环。例如,如果results[2]results[3] 都是短字符串,则到达j==2 并擦除第二个元素——这会将之后的所有内容移到一个槽中,因此results[3] 的短字符串现在位于results[2] .然后for 循环立即将j 增加到3,因此您永远不会检查现在为results[2] 的第二个短字符串。

    第二个递归循环确实负责正确地“修复”它,但你是对的,这很愚蠢。

    std::remove_if 非常适合这个。请注意,它实际上并没有从向量本身中删除任何内容,它只是将元素向下滑动并在最后留下垃圾,因此我们之后调用 vector::erase 将向量缩小到正确的大小:

    vector<string> eraselower(vector<string> results, int itemsnum){ 
        //erases all elements in vector which are not long enough
        results.erase( std::remove_if( results.begin(), results.end(),
            [itemsnum](const std::string& s) { return s.length() < itemsnum; } ),
            results.end() );
    
        return results;
    }
    

    您可能需要考虑通过非常量引用获取向量,而不是通过副本传递然后返回另一个修改后的向量。

    【讨论】:

      【解决方案3】:

      erase-remove 习惯用法有效,但我个人更喜欢即使 C++ 初学者也易于阅读的解决方案。我会做以下事情:

      vector<string> eraselower(const vector<string> & strings, int itemsnum)
      {
          vector<string> res;
          res.reserve(strings.size());
          for (const string & s: strings) {
              if (s.length() >= itemsnum) {
                  res.push_back(s);
              }
          }
          return res;
      }
      

      【讨论】:

      • “易读”是高度主观的。其他解决方案基本上说明了正在做什么remove_iferase 等,for 循环不传达此信息。
      • 虽然我知道为什么 for 循环 应该 更容易被初学者阅读,但我认为如果你理解这两个概念(你的和 remove_if 语法),那么第二个更具可读性和简单性
      • @Fureeish 我同意,这是非常主观的。初学者会发现我的解决方案更具可读性。专家可能会发现擦除删除习语更具可读性。我个人可以很好地阅读两者(现在我查找了擦除删除成语)。我的观点是,我更喜欢编写初学者而不是专家更易读的代码,因为后者在编辑代码时不太可能引入错误。 :)
      • @Boris -- 因为后者不太可能引入错误 -- 它更有可能通过手动编码 for 循环来引入错误。当给定正确的参数时,算法函数永远不会失败——在大多数情况下,算法函数中的错误(错别字)会导致编译器错误。 for 循环可能会失败,例如 for (int i = 0; i &lt; 10;j++) -- 你见过多少次在嵌套循环中犯过这个错误(混淆了 ij)?
      • @PaulMcKenzie “给定正确参数时,算法函数永远不会失败。”:正确使用 for 循环也不会失败。我的观点是,与错误地使用 for 循环相比,您更可能错误地使用擦除删除习语。尤其是 for-range 循环。
      猜你喜欢
      • 1970-01-01
      • 2020-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-03
      • 2021-03-05
      相关资源
      最近更新 更多