是否有真正简洁的方法可以做'如果没有收集'测试?

时间:2014-07-03 04:09:47

标签: c++ c

所以你有一个集合,你想看看它中没有任何项目通过测试。如果任何通过测试很容易,并且看起来像这样:

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

但要做相反的事情,如果没有通过测试,我无法想到一个真正巧妙的方法来做到这一点,以下是我能提出的方法:

// 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.
{
    //...
}

所以简而言之,我的问题是:如果没有“收集”测试,是否有真正干净的方法?如果没有,是否有理由说上述内容不是一个好的语言特色?

编辑: 我立刻后悔在标签中加入c ++。我知道有很好的功能可以做到这一点,但假设升级库或诸如此类,也是用c / c ++编写的,大概是他们遇到了同样的问题。即使这些函数内置于该语言中,在这种情况下,“只是调用此函数”并不是我所寻找的答案。

所以也许我会专注于我的问题的最后一部分:有没有理由说上面的内容不是一个好的语言功能? 在我看来没有它就像没有'else'关键字与'if'

一起使用

6 个答案:

答案 0 :(得分:5)

对于C ++来说,它非常简单(C ++ 11 with none_of,C ++ 14 with 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.
}

答案 1 :(得分:4)

“真正整洁”听起来有点基于意见,但这里有几个选择:

#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 pass\n";
}

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 pass\n";
}

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 pass\n";
}

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 pass\n"; 
}

int main() {
  std::vector<int> collection{4,2,10,3};
  printIfNonePass1(collection);
  printIfNonePass2(collection);
  printIfNonePass3(collection);
  printIfNonePass4(collection);
}

答案 2 :(得分:1)

我喜欢通过比较迭代器和最大值

来执行不匹配场景
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
}

答案 3 :(得分:1)

不需要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:编辑:回答问题。

答案 4 :(得分:0)

我认为您对算法的内部实现感兴趣,但没有应用标准算法。

通常循环按以下方式编写

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程序。

答案 5 :(得分:-1)

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

1992年,我完成了一个完整的提议和实现的正交控制结构集,可用于多种语言,并且包含了你请求的结构,这只是为了确认参数的重复性和需要的有效性。

C ++的功能虽然允许优雅的解决方案,但不能解决任何需要。

您已经提出的替代解决方案是将您需要的代码放在for构造中。因此,当函数finalizationCode()应该返回false时,代码将变得明显。

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

放置||可能更好构造而不是if(?:)。 那么在那种情况下:

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

无论如何,只有在条件i<collectionSize时才会执行finalizationCode 是假的。