具有不同条件的多个 for 循环

Multiple for loops with different conditions

我试图在 array/list 中找到一个具有一些严格条件的元素。如果 none 个元素满足严格条件,我将尝试以宽松的条件再次找到该元素。

for( ele : list) {
    if(con1 && cond2 && cond3) {
        return ele;
    }
}    
for( ele : list) {
    if(con1 && cond2) {
        return ele;
    }
}
.....

我是否应该每次都添加一个条件宽松的 for 循环?有没有更好的方法?

更好意味着更少的编码和良好的代码可读性。

您的描述非常含糊,但我怀疑您正在寻找类似(不完整 pseudo-code)的内容。

  //  assuming the relaxed conditions are a subset of the strict conditions

whatever_type relaxed_return_value;
bool relaxed_found = false;

for (auto &element : some_list)
{
     if (cond1 && cond2)            //   check relaxed conditions first
     {
          if (cond3)                 // check remaining strict conditions
          {
              return element;    // return immediately on matching strict conditions
          }
          else if (!relaxed_found)
          {
               relaxed_return_value = element;
               relaxed_found = true;
          }
     }
}
if (relaxed_found)
   return relaxed_return_value;
else
   indicate_no_value_found();

如果找到符合严格条件的元素,则立即执行上述returns,否则继续跟踪第一个符合宽松条件的元素。如果循环完成,则没有匹配严格条件的元素,并识别第一个匹配宽松条件(如果有)的结果。

如果 whatever_type 的值(即元素的值)可以指示没有数据(例如,它是一个指针,而 NULL 指示它什么都不指向),则逻辑可以简化为以上(例如,不需要 bool 值来跟踪是否已找到符合宽松标准的结果)。

至于这是否"better",那是完全主观的。这种方法相对于两个循环的主要优点是,如果没有元素满足严格要求,则不会重复测试。缺点是额外 book-keeping 跟踪宽松测试的第一场比赛,直到根据严格标准检查所有元素。

基本答案

我想这在很大程度上取决于条件的数量和复杂程度。如果只有三个单独的条件,那么是的,我会编写类似于您的代码的内容。它简单易读和易于维护。


在更复杂的情况下

如果有更多条件(比如 10 个左右)或者您预计需要添加更多条件,您可以考虑将 lambda 与向量一起使用:

// sample conditions for integers. Most strict condition is
// an even integer greater than 2 and less than 10
const std::vector<std::function<bool(int)>> conditions{
    [](int elem) {return elem < 10;},
    [](int elem) {return elem > 2;},
    [](int elem) {return elem % 2 == 0;}
    // add as many more conditions you wish...
    // top condition is the one that will be relaxed first
};


// This will bit-by bit relax the conditions by ignoring more and more of them
auto start_iterator = conditions.begin();
while (start_iterator != conditions.end())
{
    for (const auto& elem : list)
    {
        bool fulfills_all = std::all_of(start_iterator, conditions.end(), [] (std::function<bool(int)> cond) {
            // for each active condition, test the condition on the element
            return cond(elem);
        });

        if (fulfills_all)
            return elem;
    }

    // If we get here, that means no element fulfilled all the conditions. 
    // Relax them by ignoring one more
    start_iterator++;
}

// If we reach this point, then no element fulfilled even the most relaxed condition

还没有真正测试过这个,所以一些语法可能有点生疏,但它的总体思路应该是可行的。在向量的 std::function 包装器中使用 lambda 允许大量条件只需编码一次,并且 std::all_of 允许我们迭代许多条件并验证它们中的每一个都满足某个元素。

这需要 <functional><algorithm> headers。

如果您不熟悉 std::functionstd::any_of 那么这些是有用的网站:

http://en.cppreference.com/w/cpp/utility/functional/function

http://en.cppreference.com/w/cpp/algorithm/all_any_none_of