简体   繁体   English

使用STL查找向量中的所有元素

[英]using STL to find all elements in a vector

I have a collection of elements that I need to operate over, calling member functions on the collection: 我有一个需要操作的元素的集合,在集合上调用成员函数:

std::vector<MyType> v;
... // vector is populated

For calling functions with no arguments it's pretty straight-forward: 对于不带参数的调用函数,它非常简单:

std::for_each(v.begin(), v.end(), std::mem_fun(&MyType::myfunc));

A similar thing can be done if there's one argument to the function I wish to call. 如果要调用的函数只有一个参数,则可以执行类似的操作。

My problem is that I want to call a function on elements in the vector if it meets some condition. 我的问题是,如果满足某种条件,我想在向量中的元素上调用函数。 std::find_if returns an iterator to the first element meeting the conditions of the predicate. std::find_if将迭代器返回到满足谓词条件的第一个元素。

std::vector<MyType>::iterator it  = 
      std::find_if(v.begin(), v.end(), MyPred());

I wish to find all elements meeting the predicate and operate over them. 我希望找到所有符合谓词的元素并对其进行操作。

I've been looking at the STL algorithms for a " find_all " or " do_if " equivalent, or a way I can do this with the existing STL (such that I only need to iterate once), rather than rolling my own or simply do a standard iteration using a for loop and comparisons. 我一直在寻找等效的“ find_all ”或“ do_if ”的STL算法,或者我可以使用现有STL做到这一点的一种方法(这样,我只需要迭代一次),而不是自己滚动或简单地执行使用for循环和比较的标准迭代。

Boost Lambda makes this easy. Boost Lambda使此变得容易。

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/if.hpp>

std::for_each( v.begin(), v.end(), 
               if_( MyPred() )[ std::mem_fun(&MyType::myfunc) ] 
             );

You could even do away with defining MyPred(), if it is simple. 如果很简单,您甚至可以取消定义MyPred()的操作。 This is where lambda really shines. 这就是lambda真正的光芒所在。 Eg, if MyPred meant "is divisible by 2": 例如,如果MyPred的意思是“可以被2整除”:

std::for_each( v.begin(), v.end(), 
               if_( _1 % 2 == 0 )[ std::mem_fun( &MyType::myfunc ) ]
             );


Update: Doing this with the C++0x lambda syntax is also very nice (continuing with the predicate as modulo 2): 更新:使用C ++ 0x lambda语法执行此操作也非常好(继续谓词为模2):

 std::for_each( v.begin(), v.end(), [](MyType& mt ) mutable { if( mt % 2 == 0) { mt.myfunc(); } } ); 

At first glance this looks like a step backwards from boost::lambda syntax, however, it is better because more complex functor logic is trivial to implement with c++0x syntax... where anything very complicated in boost::lambda gets tricky quickly. 乍一看,这似乎比boost :: lambda语法倒退了一步,但这样做更好,因为使用c ++ 0x语法实现更复杂的函子逻辑是微不足道的...在boost :: lambda中,任何非常复杂的事情都会变得棘手很快。 Microsoft Visual Studio 2010 beta 2 currently implements this functionality. Microsoft Visual Studio 2010 beta 2当前实现了此功能。

I wrote a for_each_if() and a for_each_equal() which do what I think you're looking for. 我写了一个for_each_if()for_each_equal()来完成我认为您要寻找的事情。

for_each_if() takes a predicate functor to evaluate equality, and for_each_equal() takes a value of any type and does a direct comparison using operator == . for_each_if()使用谓词函子来评估相等性, for_each_equal()使用任意类型的值,并使用operator ==进行直接比较。 In both cases, the function you pass in is called on each element that passes the equality test. 在这两种情况下,传递给您的函数都会在通过相等性测试的每个元素上调用。

/* ---

    For each
    25.1.1

        template< class InputIterator, class Function, class T>
            Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f)

        template< class InputIterator, class Function, class Predicate >
            Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f)

    Requires:   

        T is of type EqualityComparable (20.1.1) 

    Effects:    

         Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold:

            1:  *i == value
            2:  pred(*i) != false

    Returns:    

        f

    Complexity: 

        At most last - first applications of f

    --- */

    template< class InputIterator, class Function, class Predicate >
    Function for_each_if(InputIterator first, 
                         InputIterator last, 
                         Predicate pred, 
                         Function f)
    {
        for( ; first != last; ++first)
        {
            if( pred(*first) )
                f(*first);
        }
        return f;
    };

    template< class InputIterator, class Function, class T>
    Function for_each_equal(InputIterator first, 
                            InputIterator last, 
                            const T& value, 
                            Function f)
    {
        for( ; first != last; ++first)
        {
            if( *first == value )
                f(*first);
        }
        return f;
    };

Is it ok to change the vector? 可以更改向量吗? You may want to look at the partition algorithm. 您可能需要查看分区算法。
Partition algorithm 分割算法

Another option would be to change your MyType::myfunc to either check the element, or to take a predicate as a parameter and use it to test the element it's operating on. 另一个选择是更改MyType::myfunc以检查元素,或将谓词用作参数并使用它来测试正在操作的元素。

std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin();
MyPred my_pred;
while(true) {
    i = std::find_if(i, v.end(), my_pred);
    if (i == v.end())
        break;
    matches.push_back(*i);
}

For the record, while I have seen an implementation where calling end() on a list was O(n), I haven't seen any STL implementations where calling end() on a vector was anything other than O(1) -- mainly because vector s are guaranteed to have random-access iterators. 作为记录,虽然我看到了在list上调用end()为O(n)的实现,但我没有看到在vector上调用end()不同于O(1)的任何STL实现-主要是因为保证vector s具有随机​​访问迭代器。

Even so, if you are worried about an inefficient end() , you can use this code: 即使这样,如果您担心end()的效率低下,也可以使用以下代码:

std::vector<int> v, matches;
std::vector<int>::iterator i = v.begin(), end = v.end();
MyPred my_pred;
while(true) {
    i = std::find_if(i, v.end(), my_pred);
    if (i == end)
        break;
    matches.push_back(*i);
}

For what its worth for_each_if is being considered as an eventual addition to boost. 对于它的价值for_each_if被认为是最终的提升。 It isn't hard to implement your own. 自己实现并不难。

Lamda functions - the idea is to do something like this Lamda函数-想法是做这样的事情

for_each(v.begin(), v.end(), [](MyType& x){ if (Check(x) DoSuff(x); })  

Origial post here . 原文在这里

You can use Boost.Foreach : 您可以使用Boost.Foreach

BOOST_FOREACH (vector<...>& x, v)
{
    if (Check(x)
        DoStuff(x);
}

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

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