2014-07-03 46 views
3

所以你有一個集合,你想看看它中的任何項目是否通過測試。做如有遍測試是容易的,會是這個樣子:有沒有真正乾淨的方法來做'如果沒有收藏'測試?

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 ollection'測試?如果沒有,是否有一個原因爲什麼上述不會是一個很好的語言功能?

編輯: 我立即後悔將C++放入標籤。我知道有很好的功能可以做到這一點,但假設boost庫或其他類型的文件也是用c/C++編寫的,可能他們遇到了同樣的問題。即使這些功能是建立在語言的基礎上,說'只是調用這個函數'並不是我在這種情況下尋找的答案。

所以也許我會專注於我的問題的最後一部分:是否有一個原因,爲什麼上述不會是一個很好的語言功能? 在我看來,沒有它會像'沒有'關鍵字去'如果'

+0

這取決於數據結構。 – Rapptz

+9

對於C++,[有一些很好的功能](http://en.cppreference.com/w/cpp/algorithm/all_any_none_of)。 –

+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 
} 
+2

你喜歡爲每個循環迭代測試循環變量_twice_? – Blastfurnace

+0

恩,那不是他在做什麼?我喜歡這種方式,它仍然不是很理想,因爲它在其他方法中不需要檢查,但至少創建了另一個變量inst。 – matt

+2

@matt自Blastfurnace的評論以來,答案已被編輯。 –

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); 
} 
-1

在我看來,有控制結構在許多語言ç沒有包括orthgonality。 需求是顯而易見的,並且該語言應該簡化程序員的工作,儘管在控制結構方面沒有太多的工作和/或改變在那個方向上完成。

在1992年,我完成了一套完整的控制結構的正交設置和實現,可以在很多語言中使用,並且包含了您請求的構造,這只是爲了確認參數的反覆性,需求的有效性。

C++的功能在允許優雅的解決方案的時候,並不需要任何方式解決。

您已經介紹的另一種解決方案是將您需要的代碼放入for構造中。所以代碼會變得像下面這樣,而函數finalizationCode()應該返回false。

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

可能不如把||構造而不是if(?:)。 因此,在這種情況下:

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

據反正guaranted是finalizationCode只會在條件i<collectionSize 是假執行。

5

對於C++這是很瑣碎的(C++ 11 none_of,C++ 14的自動拉姆達)

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 
}); 

我分配到這裏一個布爾值,但你可以一樣容易,如果把它包在聲明(假設名爲MatchCondition,拉姆達會工作的現有功能或仿函數對象,但這是很多的,如果條件讀):

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

不需要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:nd edit:回答這個問題。

+0

雖然是真的,並且很好的被認識到,但是none_of更簡潔,而C++ 11已經出現了大約3年。 – M2tM

+0

@ M2tM增加了C++ 11解決方案。 – Tobias

+0

最初的問題是none_of,你可以做!any_of。你的心在正確的地方,但答案已經發布。 – M2tM

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程序中該方法被寫入。

相關問題