2014-09-26 49 views
6

由於C++ 11在算法庫中有all_of, any_of and none_of來確定謂詞是否適用於某個範圍的所有元素或任何元素。到這些算法一項所述的單次調用返回的信息的1位,而對於一個特定的範圍和謂語有4種可能性:確定謂詞是否適用於某個範圍的某個或某些元素

  • 謂詞上的所有元素和沒有元素成立:範圍爲空;
  • 謂詞適用於所有元素(且範圍不爲空);
  • 謂詞在任何元素上都沒有(並且範圍不爲空);
  • 謂詞對某些元素有效,但不是全部元素。

是否有簡明有效的方法來查找此信息?調用all_of然後none_of是一種可能性,但是(a)不能在單程範圍內工作,並且(b)恰好對必要以上的謂詞進行評估。 Boost會被接受。

+2

我覺得自制是你唯一的選擇 – sp2danny 2014-09-26 10:12:51

+0

你可以用'find_first_of的兩個電話實現自己的功能(一次用謂語,一次用否定)。或者另一種想法:先手動檢查,然後應用'all_of'或'none_of'。 – Csq 2014-09-26 10:17:31

+0

@Csq我已經用第一個選項做出了答案 - 你可以用第二個選項做出答案。 – Angew 2014-09-26 10:18:26

回答

10

如果您手動檢查第一個元素並根據結果在all_ofnone_of之間進行選擇,則可以消除(a)(b)問題。

代碼(從@Angew借用enum):

enum class Result { 
    empty, all, none, some 
}; 

template <class FwIt, class Pred> 
Result examine_range(FwIt from, FwIt to, Pred pred) 
{ 
    if (from == to) return Result::empty; 
    if (pred(*from)) { 
    ++from; 
    return all_of(from,to,pred) ? Result::all : Result::some; 
    } else { 
    ++from; 
    return none_of(from,to,pred) ? Result::none : Result::some; 
    } 
} 
+0

我喜歡這個解決方案的簡單性。從我所看到的,你甚至可以放寬'from' /'to'的要求,這樣你就可以使用'InputIterator'而不是'ForwardIterator'。 – Andrew 2014-09-26 12:37:02

1

難道我理解這個問題錯誤,或者是這個東西,你可以通過std::accumulate嗎?

using eana = std::tuple<bool, bool, bool, bool>; 

template <typename T, typename FwdIt, typename Pred> 
auto empty_all_none_any(FwdIt begin, FwdIt end, Pred predicate) -> eana { 
    auto result = eana{begin == end, begin != end, begin != end, false}; 
    result = std::accumulate(begin, end, result, [&](eana& res, T& val) { 
    if (predicate(val)) { 
     std::get<2>(res) = false; 
     std::get<3>(res) = true; 
    } 
    else { 
     std::get<1>(res) = false; 
    } 
    return res; 
    }); 
    return result; 
} 
+2

您的解決方案的問題在於它計算所有元素的謂詞。但是,例如,如果第一個元素的謂詞值爲[true,false,true,...],則可以在第三個元素之後退出,表示謂詞在一些元素上但不是全部元素上保留。 – Csq 2014-09-26 11:31:26

+0

好,好點。這可能會嫁接到我的代碼上,但是在那個時候,你的解決方案變得更加優雅(如果它還沒有的話)。順便說一句,有沒有更好的方式擺脫積累,而不是拋出異常? – Kolja 2014-09-26 11:43:51

0

這是我首選的算法(枚舉從@Angew):

enum class Result { 
    empty, all, none, some 
}; 
template<class InputIt, class UnaryPredicate> 
Result examine_range(InputIt first, InputIt last, UnaryPredicate p) 
{ 
    bool all = true, none = true; 
    for (; first != last && (all || none); ++first) 
     (p(*first) ? none : all) = false; 
    return all ? (none ? Result::empty : Result::all) 
     : (none ? Result::none : Result::some); 
} 
0

你可以用你所描述的標準庫函數做到這一點。同時測試的任何元素是否是真實的,任何元素是否是假的,那麼根據這個表合併結果:

   any true | none true 
      ====================== 
any false | mixed | all false | 
none false | all true | empty | 
+1

(a)不能在單程範圍內工作,並且(b)恰好對必要以上的謂詞進行評估。 – ecatmur 2014-10-01 10:21:59

相關問題