简体   繁体   English

是否有类似std :: accumulate的东西在迭代器上运行?

[英]Is there something like std::accumulate that operates on iterators?

What I want: An iterator to the next element after another iterator (let's call it base iterator) that's lexicographically larger (>) than the element pointed to by that base iterator (that is, if I have an 'a' and the rest is [c,d,a,b] I want the b, or rather the iterator to b). 我想要的:一个迭代器到另一个迭代器之后的另一个迭代器(让我们称之为基础迭代器),它的词典大于(>)比该基础迭代器所指向的元素(也就是说,如果我有一个'a',其余的是[c,d,a,b]我想要b,或者更喜欢b)的迭代器。 I'm not aware of an <algorithm> function that could be used for that, so I'm doing it "by hand" if you so will. 我不知道可以使用的<algorithm>函数,所以如果你愿意的话我会“手工”。

How I think I could do it: run this lambda with some kinda of accumulate over the collection: 我怎么我能做到:运行这个lambda,在集合上有一些积累:

[mism.first](it_t acc, it_t el) 
{ 
    if(*el > *mism.first) { 
        return iter_min(acc,el); 
    } 
    return acc; 
}

(iter_min(a,b) is a when *a<=*b, mism.first is said "base iterator"). (iter_min(a,b)是* a <= * b时,mism.first是“base iterator”)。 But since accumulate works on values rather than iterators, I can't. 但是由于累积在值而不是迭代器上工作,我不能。 Is there something like this for iterators? 迭代器有这样的东西吗? If not, would you say I should just write it (I don't think I'll be overexercising myself with that) or am I just going at it the "wrong" way (by the way, I'd be ending up swapping the elements pointed to by the iterators. I know this sounds an awful lot like next_permutation, but while what I'm doing has a lot to do with permutations, it's not quite what I want)? 如果没有,你会说我应该写它(我不认为我会用它来过度训练)或者我只是以“错误”的方式去做(顺便说一句,我最终会换掉它)由迭代器指向的元素。我知道这听起来很可怕很多像next_permutation,但是当我在做什么有很多事情要做的排列,这是不太我想要什么)?

The easiest possibility I see is to create a range that can be iterated consisting of with successive iterators from [base, end) . 我看到的最简单的可能性是创建一个可以迭代的范围,包括来自[base, end)连续迭代器。 This is possible with the Boost.Iterators counting_iterator , but should be fairly easy to implement even without boost. 使用Boost.Iterators counting_iterator可以实现这一点,但即使没有增强也应该很容易实现。

Your proposed lambda would then work almost as is: 你提出的lambda几乎可以正常工作:

some_iterator base = ..., end = ...;
some_iterator the_next_least_thing =
  std::accumulate(boost::make_counting_iterator(base),
                  boost::make_counting_iterator(end),
                  end,
                  [=](some_iterator acc, some_iterator cur) { 
                     return (*cur > *base && (acc == end || *cur < *acc)) ? cur : acc });

To find the first element that is larger than the base, you could try to use std::find_if with a lambda predicate that returns true if the current element pointed to is larger than the element pointed to by the base iterator. 要查找大于基数的第一个元素,可以尝试将std::find_if与lambda谓词一起使用,如果指向的当前元素大于基本迭代器指向的元素,则返回true。 Since lambdas are unfortunately not polymorphic, you need to specify the type using std::iterator_traits (so that it also works for pointers). 由于lambdas遗憾的是不是多态的,你需要使用std::iterator_traits指定类型(这样它也适用于指针)。

To find the smallest element larger than the base, you do a linear scan where you repeatedly look for the first element in the remaining list that is larger than the base, and then check if it is smaller than the current minimum. 要查找大于基数的最小元素,可以进行线性扫描,重复查找剩余列表中大于基数的第一个元素,然后检查它是否小于当前最小值。 Every time you update the minimum, you also increase the iterator to the current minimum, so that you only have to look for the next candidate in the remaining section. 每次更新最小值时,也会将迭代器增加到当前最小值,这样您只需在剩余部分中查找下一个候选项。 This makes this algorithm O(N) in the number of elements N . 这使得该算法O(N)的元素数量为N

#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>

template<typename FwdIt>
FwdIt first_larger(FwdIt first, FwdIt last, FwdIt base)
{
    typedef typename std::iterator_traits<FwdIt>::value_type T;

    return std::find_if(first, last, [=](T const& elem) {
         return elem > *base;
    });
}

template<typename FwdIt>
FwdIt first_larger(FwdIt first, FwdIt last)
{
    return first_larger(first, last, first);
}

template<typename FwdIt>
FwdIt min_larger(FwdIt first, FwdIt last)
{
    typedef typename std::iterator_traits<FwdIt>::value_type T;
    auto min = last;
    auto found = false;

    for(auto it = first; it != last; ++it) {
         auto m = first_larger(it, last, first);         
         if (m == last) break;         
         it = min = m;
         found = true;        
    }
    return found? min : last;
}

int main()
{
    std::array<int,11> arr = {{ 54, 314, 5, 7, 1, -1, 0, 14, 9, 8, 6 }};

    auto b = &arr[3]; 
    auto f = first_larger(b, arr.end());
    auto m = min_larger(b, arr.end());

    std::cout << *b << "\n"; // 7
    if(f != arr.end()) std::cout << *f << "\n"; // 14
    if(m != arr.end()) std::cout << *m << "\n"; // 8 

    return 0;
}

You could probably generalize this to a function 你可以将它概括为一个函数

template<typename FwdIt, typename Pred, typename Cmp>
FwdIt min_element_if(FwdIt first, FwdIt last, Pred pred, Cmp cmp)
{
    // return iterator to smallest element satisfying Predicate
}

and other overloads that set Cmp equal to operator< etc. Unfortunately, the STL does not contain such combinations of more elementary algorithms. 以及将Cmp设置为等于operator<等的其他重载。不幸的是,STL不包含更多基本算法的这种组合。 You could look at Boost.Iterator to use filter adapters 您可以查看Boost.Iterator以使用过滤器适配器

 // equivalent to min_element_if(first, last, pred)
 min_element(boost::make_filter_iterator(first, last, pred),
             boost::make_filter_iterator(last, last, pred));

Use find_if, supplying your iterator+1 as the start point: 使用find_if,提供迭代器+ 1作为起点:

bool mycomp (char c1, char c2)
{ return lexicographical_compare(*c1,*c1,*c2,*c2); }    

vector<char>::iterator nextBigger = find_if(it+1,end,mycomp)

Adapted from std lib's lexicographic_compare routine and find_if . 改编自std lib的lexicographic_compare例程find_if

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM