2015-06-22 71 views
6

在這個問題的評論is-there-a-way-to-iterate-over-at-most-n-elements-using-range-based-for-loop還有一個問題 - 這是可能有一個容器上的「索引視圖」,即有一些索引過濾出來的子範圍。一種通過索引過濾範圍的方法,只從過濾後的索引獲取min_element?

此外,我遇到了一個問題,以找出一些範圍內的最小值,並篩選出一些索引。

I.e.是有可能取代這樣的代碼,如下面性病和/或升壓算法,過濾器 - 以使其更具有可讀性和可維護:

template <typename Range, typename IndexPredicate> 
auto findMin(const Range& range, IndexPredicate ipred) 
    -> boost::optional<typename Range::value_type> 
{ 
    bool found = false; 
    typename Range::value_type minValue{}; 
    for (std::size_t i = 0; i < range.size(); ++i) 
    { 
     if (not ipred(i)) 
      continue; 
     if (not found) 
     { 
      minValue = range[i]; 
      found = true; 
     } 
     else if (minValue > range[i]) 
     { 
      minValue = range[i]; 
     } 
    } 
    if (found) 
    { 
     return minValue; 
    } 
    else 
    { 
     return boost::none; 
    } 
} 

只是要使用這樣的:

#include <iostream> 
#include <vector> 

int main() { 
    std::vector<float> ff = {1.2,-1.2,2.3,-2.3}; 
    auto onlyEvenIndex = [](auto i){ return (i&1) == 0;}; 

    auto minValue = findMin(ff, onlyEvenIndex); 
    std::cout << *minValue << std::endl; 
} 

回答

6

使用最近標準range-v3 proposal

#include <range/v3/all.hpp> 
#include <iostream> 
#include <vector> 

int main() 
{ 
    std::vector<float> rng = {1.2,-1.2,2.3,-2.3}; 

    auto even_indices = 
     ranges::view::iota(0ul, rng.size()) | 
     ranges::view::filter([](auto i) { return !(i & 1); }) 
    ; 
    auto min_ind = *ranges::min_element(
     even_indices, [&rng](auto L, auto R) { 
     return rng[L] < rng[R]; 
    }); 
    std::cout << rng[min_ind]; 
} 

Live Example。請注意,語法大致類似於Boost.Range,但完全改造以利用C++ 14(廣義lambda表達式,自動返回類型演繹等)。

+0

這是對C++ 17的建議嗎?我可以在gcc4.9中使用它嗎? – PiotrNycz

+0

Gcc 4.9在C++ 11模式下工作,在C++ 14模式下使用clang(gcc 5.1有一些防止C++ 14模式的bug)。該提案正在跟蹤C++ 17或TS,可能與C++ 17並存。請參閱https://github.com/ericniebler/range-v3 – TemplateRex

3

將溶液這是想超越在C++中過濾範圍的自然方式。我的意思是 - 我們需要過濾索引的範圍,而不是範圍的值。但是從哪裏我們得到了指數的範圍?有辦法得到指數的範圍 - boost::irange。所以 - 看到這一點:

使用升壓
#include <boost/range/irange.hpp> 
#include <boost/range/adaptor/filtered.hpp> 
#include <boost/range/algorithm/min_element.hpp> 
#include <functional> 

template <typename Range, typename IndexPredicate> 
auto findMin(const Range& range, IndexPredicate ipred) -> boost::optional<typename Range::value_type> 
{ 
    using boost::adaptors::filtered; 
    using boost::irange; 

    auto filtered_indexes = irange(0u, range.size()) | filtered(std::function<bool(std::size_t)>{ipred}); 

一個缺點範圍是they have problems to use raw lambdas - 所以這就是爲什麼我需要使用std::function

Nest步驟與使用boost::min_element一樣簡單 - 唯一要記住的是您應該比較值。不只是指標:

auto lessByValue = [&range] (auto lhs, auto rhs) 
{ 
     return range[lhs] < range[rhs]; 
}; 

和最終步驟:

auto foundMin = boost::min_element(filtered_indexes, lessByValue); 
if (foundMin != std::end(filtered_indexes)) 
    return range[*foundMin]; 
else 
    return boost::none; 
2

this answer開頭於前面的問題。可選地,增加該問題中描述的任務。

增加indexT支持一個箭步模板參數size_t stride=1:更換++t;std::advance(t,stride);

添加ItB base() const { return b+**a(); }indexing_iterator(這是爲以後)。

添加template<size_t stride> using index_stride_range=range<indexT<size_t, stride>>;這是一個編譯時間跨度的索引範圍。

intersect在兩個index_stride_range s上工作。輸出是步幅gcd(lhs_stride, rhs_stride)index_stride_range。確定它的起點是另一點工作,但只有高中數學。請注意,index_rangeindex_stride_range的一種,stride=1,因此此升級也可與index_range一起使用。

升級index_filterindex_stride_range作爲第一個參數。實施是相同的(除了依靠升級intersect)。

every_nth_index<N>(offset),這是一個index_stride_range是去從offsetsize_t(-(1+(abs(offset))%stride) - (size_t(-(1+(abs(offset)%stride)))%stride)或一些這樣的(基本爲0,以在簡單情況下無限 - 額外的數學發現是等於offset + K *步幅,最大的數。適合在size_t

現在,我們得到:

auto filtered = index_filter(every_nth_index<2>(), container); 
auto it = (std::min)(filtered.begin(), filtered.end()); 

,我們有一個iterator it.base()將返回迭代器包含元素container如果it!=filtered.end();(不it.base()!=container.end(),這是不同的)。

+0

我是否有良好的感覺,這種迭代器方法也可用於從流中讀取時從每秒鐘查找最小值......我的意思是它不僅可用於迭代器是forward_iterator? – PiotrNycz

+0

@PiotrNycz上一個答案的一部分依賴於隨機訪問迭代器(因爲它存儲'start'迭代器和一個索引,並且在取消引用時執行'*(start + index)')。但是,是的,可以編寫變體以支持「跳過每一個第二個值」或其他。我只是注意到,我在鏈接問題中提供的答案几乎也是解決這個問題的答案。 – Yakk