tags:

views:

241

answers:

5

Hello, I need to find the indexes in the vector based on several boolean predicates.

ex:

vector<float> v;
vector<int> idx;

idx=where( bool_func1(v), bool_func2(v), ... );

What is the way to declare **where** function, in order to use the several user defined boolean functions over the vector?

thanks Arman.

Edit after one week

I did some complex solutions with templates. But in reality one can use already predefined valarray for my tasks. Here is the code snippet maybe one can find it useful:

  double dr=Rc/(double)Nbins, r;
  sigma.resize(Nbins);
  rr=sigma;
  valarray<double> vz(&data.vz[0], data.vz.size());
  double mvel=vz.sum()/(double)vz.size();
  for(size_t i=0l;i<Nbins;i++)
   {
   r=dr*i;
   valarray<bool> ids = (dist < r+dr) && (dist > r);//The magic valarray<bool>
   if(ids.max())
    {
    valarray<double> d=vz[ids];//we can use indirect operation.
    d-=mvel;
    d=pow(d,2.0);
    sigma[i]= sqrt(d.sum()/(double)d.size());
    rr[i]=r;
    cout<<i<<") "<<r<<" "<<sigma[i]<<endl;
    }
   }
+10  A: 
Noah Roberts
+1 for this nice solution
PeterK
WOW, With Labda it looks impressive!!!
Arman
I could be wrong but doesn't find_if return an iterator to the *first* match? Arman wants a list of *all* matching indices.
Job
@Job: You're right, but for an iterator `it` into a vector `v`, the index can be computed as `it-v.begin()`.
sbi
@Arman: If you think this is impressive wait until you see the compiler error messages when you do something wrong with this. There's some very heavy template magic going on behind the scenes, and when the compiler pukes that out for you, it's quite disgusting. (If you're using a compiler that supports C++1x lambda you might be better off using that. There is a reason the std committee built it into the language rather than using their preferred method of adding a library.)
sbi
@Noah Roberts: Now with lambda it works. I would like to pass to my where function the array of lambda closures, What type is "l::_1 < l::bind(fun, l::_1)"?
Arman
@sbi: no , I dont have any compiler errors, it compiles fine:)
Arman
Noah Roberts
@Arman - it's undefined. Make it a template parameter and then you can use any sort of predicate or binder.
Noah Roberts
@Noah Roberts: collect_if sounds nicer:) thanks I will rename it.
Arman
@Arman, @Noah Roberts: collect_if would be more simply written as the infamous missing copy_if. Unless you have pressing performance reasons to do it this way, I'd go with standard implementations of copy_if that you can find online. See: http://www.richelbilderbeek.nl/CppCopy_if.htm for one. transform_if listed below is very similar.
Owen S.
@Owen - I agree. I like the transform_if idea to get the index; I wrote my example before I saw that. A copy_if might also be valid with the one caveat that it's going to copy what it runs into (assuming it lives up to its name) instead of refer to the elements directly. Depending on use this could either be exactly what is needed or exactly not. Since Arman was looking for indexes it may very well be that a "collect_if" (or the transform_if) is what they need, but it's definitely a preferable option to look at if it meets their needs.
Noah Roberts
@Owen - of course, remove_copy_if !pred could be a better option than even finding and using a copy_if since it's already there.
Noah Roberts
@Owen S.: thanks for the link. Sorry, but your web site background is very disturbing. It is very hard to read.
Arman
@Noah Roberts just a small note: fit+1 will actually not work for forward iterators since iterator addition is only defined for random access iterators. use std::advance instead.
Christoph Heindl
@Heindl - good catch. +1
Noah Roberts
@Arman: That's because you haven't done anything wrong yet.
sbi
@Noah: What's the advantage of doing this recursively (and thereby repeatedly copying the resulting container)? Am I missing something?
sbi
@sbi - I don't know of one.
Noah Roberts
@Noah: You mean you don't know an advantage or you don't know an iterative implementation? An iterative implementation ought to be a three-liner and wouldn't needlessly copy the result. In both the recursive implementation has a disadvantage.
sbi
@Noah: Well, turns out I was wrong. It's a [four-liner](http://stackoverflow.com/questions/2999537/3001760#3001760).
sbi
@sbi - that's nice.
Noah Roberts
@Aman: lol, didn't even notice the background on that page the first time around! Not my choice either.
Owen S.
@Noah Roberts: re: remove_copy_if: I've read that the lack of copy_if was a simple oversight, so I think of it as equivalent to a standard algorithm. I wouldn't prefer remove_copy_if myself unless it actually made the code clearer.
Owen S.
A: 

I am not sure which indexes you want. Is this what you are trying to acheive:

//Function pointer declaration
typedef bool (*Predicate)(const std::vector<float>& v);

//Predicates
bool bool_func1(const std::vector<float>& v)
{
    //Implement
    return true;
}

bool bool_func2(const std::vector<float>& v)
{
    //Implement
    return true;
}


std::vector<int> where_func(const std::vector<float>& v,
                const std::vector<Predicate>& preds)
{
    std::vector<int>  idxs;
    std::vector<Predicate>::const_iterator iter = preds.begin();
    std::vector<Predicate>::const_iterator eiter = preds.end();
    for(; iter != eiter; ++iter)
    {
        if((*iter)(v))
        {
            idxs.push_back(eiter - iter);
        }   
    }

    return idxs;
}
Naveen
+1  A: 

This seems like a problem that could much easier be solved in an declarative language like Prolog. I gave it a try in C++ anyway:

typedef float type;
typedef bool (*check)(type);

std::vector<int> where(const std::vector<type>& vec,
                       const std::vector<check>& checks)
{
    std::vector<int> ret;

    for (int i = 0; i < vec.size(); i++)
    {
        bool allGood = true;

        for (int j = 0; j < checks.size(); j++)
        {
            if (!checks[j](vec[i]))
            {
                allGood = false;
                break;
            }
        }

        if (allGood)
            ret.push_back(i);
    }

    return ret;
}
Job
A: 
template<typename Vector, typename T> std::vector<int> where(const std::vector<Vector>& vec, T t) {
    std::vector<int> results;
    for(int i = 0; i < vec.size(); i++) {
        if (t(vec[i])
            results.push_back(i)
    }
    return results;
}

Overload for additional function object arguments as you wish. Use:

template<typename T> struct AlwaysAccept {
    bool operator()(const T& t) { return true; }
};
std::vector<float> floats;
// insert values into floats here
std::vector<int> results = where(floats, AlwaysAccept<float>());

Noah Robert's solution is nice, but I'm not wholly sure how I could make that work.

DeadMG
+3  A: 

You could use a predicated version of transform, if there were one. There's not one, but it is very easy to write:

template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first, 
                            InputIterator last, 
                            OutputIterator result, 
                            UnaryFunction f, 
                            Predicate pred)
{
    for (; first != last; ++first)
    {
        if( pred(*first) )
            *result++ = f(*first);
    }
    return result; 
}

Then you would need a way to make a composite of multiple predicates, so that you could express something like find_if( begin, end, condition1 && condition2 ). This, again, is easy to write:

template<typename LHS, typename RHS> struct binary_composite : public std::unary_function<Gizmo, bool>
{
    binary_composite(const LHS& lhs, const RHS& rhs) : lhs_(&lhs), rhs_(&rhs) {};

    bool operator()(const Gizmo& g) const
    {
        return lhs_->operator()(g) && rhs_->operator()(g);
    }
private:
    const LHS* lhs_;
    const RHS* rhs_;
};

Finally you need a gizmo that transform_if uses to convert an object reference to an object pointer. Surprise, surprise, easy to write...

template<typename Obj>  struct get_ptr : public std::unary_function<Obj, Obj*>
{
    Obj* operator()(Obj& rhs) const { return &rhs; }
};

Let's put this all together with a concrete example. Gizmo below is the object that you have a collection of. We have 2 predicates find_letter and find_value that we want to search for matches to in our main vector. transform_if is the predicated version of transform, get_ptr converts an object reference to a pointer, and binary_composite strings together the two composites.

#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <string>
#include <functional>
#include <vector>
using namespace std;

struct Gizmo
{
    string name_;
    int value_;
};

struct find_letter : public std::unary_function<Gizmo, bool>
{
    find_letter(char c) : c_(c) {}
    bool operator()(const Gizmo& rhs) const { return rhs.name_[0] == c_; }
private:
    char c_;
};

struct find_value : public std::unary_function<Gizmo, int>
{
    find_value(int v) : v_(v) {};
    bool operator()(const Gizmo& rhs) const { return rhs.value_ == v_; }
private:
    int v_;
};

template<typename LHS, typename RHS> struct binary_composite : public std::unary_function<Gizmo, bool>
{
    binary_composite(const LHS& lhs, const RHS& rhs) : lhs_(&lhs), rhs_(&rhs) {};

    bool operator()(const Gizmo& g) const
    {
        return lhs_->operator()(g) && rhs_->operator()(g);
    }
private:
    const LHS* lhs_;
    const RHS* rhs_;
};

template<typename LHS, typename RHS> binary_composite<LHS,RHS> make_binary_composite(const LHS& lhs, const RHS& rhs)
{
    return binary_composite<LHS, RHS>(lhs, rhs);
}


template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first, 
                            InputIterator last, 
                            OutputIterator result, 
                            UnaryFunction f, 
                            Predicate pred)
{
    for (; first != last; ++first)
    {
        if( pred(*first) )
            *result++ = f(*first);
    }
    return result; 
}

template<typename Obj>  struct get_ptr : public std::unary_function<Obj, Obj*>
{
    Obj* operator()(Obj& rhs) const { return &rhs; }
};


int main()
{   
    typedef vector<Gizmo> Gizmos;
    Gizmos gizmos;
    // ... fill the gizmo vector

    typedef vector<Gizmo*> Found;
    Found found;
    transform_if(gizmos.begin(), gizmos.end(), back_inserter(found), get_ptr<Gizmo>(), binary_composite<find_value,find_letter>(find_value(42), find_letter('a')));

    return 0;

}

EDIT:

Based on sbi's iterative approach, here's a predicated version of copy, which is more in line with the general STL paradigm, and can be used with back_insert_iterator to accomplish what's wanted in this case. It will give you a vector of object, not iterators or indexes, so the transform_if I posted above is still better for this use than copy_if. But here it is...

template<class InputIterator, class OutputIterator, class Predicate>
OutputIterator copy_if(InputIterator first, 
                       InputIterator last, 
                       OutputIterator result, 
                       Predicate pred)
{
    for (; first != last; ++first)
    {
        if( pred(*first) )
            *result++ = *first;
    }
    return result;
}
John Dibling
+1 for predicated transform
Noah Roberts
@John Dibling: Thanks John for pointing the transform_if, it is already long time in my utility collection, I use it a lot and seems to me it is a magic function:)(after your post )
Arman