有没有真正巧妙的方法来进行测试'if none in collection'?

Is there are truly neat way to do 'if none in collection' test?

本文关键字:if none collection in 测试 方法 有没有      更新时间:2023-10-16

那么您有一个集合,您想看看其中是否没有项通过测试。执行if ANY通过测试很容易,看起来像这样:

for (int i = 0; i < collectionSize; i++)
{
    if(ItemPasses(collection[i]))
    {
        // do code for if any pass
        break;
    }
}

但是要做相反的事情,如果NONE通过测试,我想不出一个真正简洁的方法来做,下面是我能想到的方法:

// nice to look at but uses an unecessary variable 'anItemPassed'
bool anItemPassed = false;
for (int i = 0; i < collectionSize; i++)
{
    if(ItemPasses(collection[i]))
    {
        anItemPassed = true;
        break;
    }
}
if (!anItemPassed)
{
    //...
}
//---------------------------------------------------------------------------------
// as efficient as possible but uses gotos.. nobody likes gotos.. lable stuff really isnt that neat.
for (int i = 0; i < collectionSize; i++)
{
    if (ItemPasses(collection[i]))
    {
        goto ItemPassed;
    }
}
    //...
ItemPassed: { }
//-------------------------------------------------------------------------
// as efficient as possible and doesnt use the rarely used (and usually poorly supported in IDEs) goto/lable stuff, but doesnt use any nice loop construct, does it all manually
int i = 0;
for (; ; )
{
    if (i >= collectionSize)
    {
        //...
        break;
    }
    if (ItemPasses(collection[i]))
    {
        break;
    }
    i++;
}

我真的不喜欢这些,我一直想知道为什么从来没有一个结构像:

for (int i = 0; i < collectionSize; i++)
{
    if (ItemPasses(collection[i]))
    {
        break;
    }
}
finally //executed if the loop terminates normally, not via breaks.
{
    //...
}

所以简而言之,我的问题是:是否有真正简洁的方法来做"if none in collection"测试?如果不是,有什么理由说明上述不是一个好的语言特性?

编辑:我立刻后悔把c++放在标签中。我知道有很好的函数可以做到这一点,但假设boost库或诸如此类的东西也是用c/c++编写的,想必它们遇到了与我相同的问题。即使这些函数是内置在语言中,说"只是调用这个函数"并不是我在这种情况下寻找的答案。

所以也许我应该把重点放在我问题的最后一部分:是否有理由说明上述不是一个好的语言特性?在我看来,没有它就像没有'else'关键字来搭配'if'

对于c++来说非常简单(c++ 11带有none_of, c++ 14带有auto lambda)

bool noneExist = std::none_of(std::begin(collection), std::end(collection), [](auto &item){
    return item.matchesCondition(); // any evaluation can go here, or you could just supply an existing functor instead of a lambda
});

我在这里赋值给一个bool值,但是您也可以很容易地将它包装在if语句中(这里假设存在一个名为MatchCondition的函数或函子对象,lambda也可以,但是在if条件中要读的东西太多了):

if(std::none_of(std::begin(collection), std::end(collection), MatchCondition)){
    //run your "if none of the above matched" code here.
}

和旧的c++ 98补全方法:

if(std::find_if(collection.begin(), collection.end(), MatchCondition) == collection.end()){
    //run your "if none of the above matched" code here.
}

" really neat"听起来有点主观,但这里有几个选项:

#include <iostream>
#include <algorithm>
#include <vector>
bool itemPasses(int i) {
  return i > 10;
}
void printIfNonePass1(const std::vector<int>& collection) {
  if (std::none_of(collection.cbegin(), collection.cend(), itemPasses))
    std::cout << "None passn";
}
void printIfNonePass2(const std::vector<int>& collection) {
  auto iter = collection.cbegin();
  for(; iter != collection.cend(); ++iter) {
    if (itemPasses(*iter))
      break;
  }
  if (iter == collection.cend())
    std::cout << "None passn";
}
void printIfNonePass3(const std::vector<int>& collection) {
  size_t i = 0;
  for(; i != collection.size(); ++i) {
    if (itemPasses(collection[i]))
      break;
  }
  if (i == collection.size())
    std::cout << "None passn";
}
bool checkIfNonePass(const std::vector<int>& collection) {
  for(int item : collection) {
    if (itemPasses(item))
      return false;
  }
  return true;
}
void printIfNonePass4(const std::vector<int>& collection) {
  if (checkIfNonePass(collection))
    std::cout << "None passn"; 
}
int main() {
  std::vector<int> collection{4,2,10,3};
  printIfNonePass1(collection);
  printIfNonePass2(collection);
  printIfNonePass3(collection);
  printIfNonePass4(collection);
}

我喜欢通过将迭代器与最大值进行比较来执行不匹配场景来实现这一点。

int i;
for (i = 0; i < collectionSize; i++)
{
    if (ItemPasses(collection[i]))
    {
        // do code for if any pass
        break;
    }
}
if (i == collectionSize)
{
    // perform no-match operations
}

不需要c++14或c++11。像这样的代码应该可以满足您的需求。

if (find_if(collection.begin(), collection.end(), ItemPasses) == collection.end()) {
    //code if none passes
}

编辑:添加c++11解决方案作为对注释的回应。

if (none_of(collection.begin(), collection.end(), ItemPasses)) {
    //code if none passes
}

2:并编辑:回答问题

我想你感兴趣的是算法的内部实现,而不是应用标准算法。

通常循环是这样写的

CollectionType::size_type i = 0;
while ( i < collectionSize && !ItemPasses(collection[i]) ) ++i;
return ( i == collectionSize );

同样可以用迭代器

来写
while ( first != last && !ItemPasses( *first ) ) ++first;
return ( first == last );

在我看来,包括C在内的许多语言的控制结构中没有正交性。需求是显而易见的,语言应该简化程序员的工作,尽管在控制结构方面没有太多的工作和/或改变。

在1992年,我已经完成了一个正交控制结构集的完整建议和实现,它可以在许多语言中使用,并且包含了您要求的构造,这只是为了确认参数的递归性和需求的有效性。

c++的函数虽然允许一个优雅的解决方案,但不以任何方式解决需要。

您已经提供的另一种解决方案是将所需的代码放入for构造中。因此,代码将如下所示,而函数finalizationCode()应该返回false。

for (int i = 0; i < collectionSize ? true : finalizationCode(); i++)

如果使用if (?):)。在这种情况下:

for(int i=0 ; i < collectionSize || finalizationCode() ;i++)

无论如何,finalizationCode将保证仅在条件i<collectionSize时执行是假的。