Help with STL std::remove_if

Help with STL std::remove_if

Post by PSI » Sat, 17 May 2003 19:23:55



I have the following data structures:

vector<int>   data;
vector<bool> flags;

My objectives are:

1) remove all elements from data where corressponding flag is true
2) do it the STL way ;-)

so I'm trying to do something like:

data.erase( remove_if( flags.begin(), flags.end(),
bind1st(equal_to<bool>(), true)), data.end());

but it's not quite right. Can anyone point me in the right direction?

Thanks


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by Raoul Goug » Sun, 18 May 2003 00:50:03



Quote:

> I have the following data structures:

> vector<int>   data;
> vector<bool> flags;

> My objectives are:

> 1) remove all elements from data where corressponding flag is true
> 2) do it the STL way ;-)

> so I'm trying to do something like:

> data.erase( remove_if( flags.begin(), flags.end(),
> bind1st(equal_to<bool>(), true)), data.end());

> but it's not quite right. Can anyone point me in the right

direction?

Looks to me like it shouldn't even compile - the call to remove_if
will return a std::vector<bool>::iterator which I can't believe you
can pass to std::vector<int>::erase.

To fix it, wouldn't it be easier to keep the flags and the data in one
vector? e.g. std::vector<std::pair<bool, int> >. You could then do the
remove_if using std::less and std::make_pair (true, 0). Either that or
use a functor adapater that selects the first element of the pair.

--
Raoul Gough
see http://home.clara.net/raoulgough/ for my work availability


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by John Potte » Sun, 18 May 2003 01:26:34



Quote:> vector<int>   data;
> vector<bool> flags;
> My objectives are:
> 1) remove all elements from data where corressponding flag is true
> 2) do it the STL way ;-)

To be proper, you would need another structure and some simple things.
I used the _Selects from g++, but they are available elsewhere.

    vector<pair<int, bool> > t;
    transform(data.begin(), data.end(), flags.begin(), back_inserter(t),
            make_pair<int, bool>);
    t.erase(remove_if(t.begin(), t.end(),
            _Select2nd<pair<int, bool> >()), t.end());
    data.resize(t.size());
    transform(t.begin(), t.end(), data.begin(),
            _Select1st<pair<int, bool> >());

If you can use a special int value such as -1, you could do it in two
steps.

int selector (int i, bool b) {
    return b ? -1 : i;
    }

    transform(data.begin(), data.end(), flags.begin(), data.begin(),
            selector);
    data.erase(remove(data.begin(), data.end(), -1), data.end());

If you prefer to violate the rules and use a predicate with
side-effects,
the following will do the job.

template <class Iter, class T>
struct Picker {
    Iter& it;
    Picker (Iter& it) : it(it) {
        }
    bool operator() (T const&) {
        return *it++;
        }
    };

    vector<bool>::const_iterator t(flags.begin());
    data.erase(remove_if(data.begin(), data.end(),
            Picker<vector<bool>::const_iterator, int>(t)), data.end());

In any case, clear the flags.

    flags = vector<bool>(data.size());

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by witol » Sun, 18 May 2003 09:13:53



> I have the following data structures:

> vector<int>   data;
> vector<bool> flags;

> My objectives are:

> 1) remove all elements from data where corressponding flag is true
> 2) do it the STL way ;-)

> so I'm trying to do something like:

> data.erase( remove_if( flags.begin(), flags.end(),
> bind1st(equal_to<bool>(), true)), data.end());

> but it's not quite right. Can anyone point me in the right direction?

You are trying to erase elements of data, by specifying the range with
the first iterator that "points" into flags, and second into data.


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by PSI » Sun, 18 May 2003 09:15:28






>> I have the following data structures:

>> vector<int>   data;
>> vector<bool> flags;

>> My objectives are:

>> 1) remove all elements from data where corressponding flag is true
>> 2) do it the STL way ;-)

>> so I'm trying to do something like:

>> data.erase( remove_if( flags.begin(), flags.end(),
>> bind1st(equal_to<bool>(), true)), data.end());

>> but it's not quite right. Can anyone point me in the right
>direction?

>Looks to me like it shouldn't even compile - the call to remove_if
>will return a std::vector<bool>::iterator which I can't believe you
>can pass to std::vector<int>::erase.

>To fix it, wouldn't it be easier to keep the flags and the data in one
>vector? e.g. std::vector<std::pair<bool, int> >. You could then do the
>remove_if using std::less and std::make_pair (true, 0). Either that or
>use a functor adapater that selects the first element of the pair.

Thanks for the reply.

You are quite correct. When I wrote ".. not quite right", it was
because it ( and other variations ) wouldn't compile. My apologies for
lake of clarity.

The code snip posed is a simplification from a real app that I was
using to experiment  with.  In reality the data and flag vectors exist
in separate objects and typically contain approx 100,000 elements. The
data  vector is also actually a vector of complex objects. Because of
this I was trying  to avoid the  creation of  a temporary vector
containing both data and flags so that the remove_if you suggest could
be used.

On a side note:
I hadn't seen your suggestion  of vectors of pairs before ( I would
likely have used  a struct to create the pair). Having now seen it,
the technique should have been obvious to me :-(. As my original post
indicated I'm trying to get used to the STL way so I've learned
something new - Thanks


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by PSI » Sun, 18 May 2003 09:26:12





>> vector<int>   data;
>> vector<bool> flags;
>> My objectives are:
>> 1) remove all elements from data where corressponding flag is true
>> 2) do it the STL way ;-)

{ snip unreferenced -mod/jep }

Quote:>If you can use a special int value such as -1, you could do it in two
>steps.
>int selector (int i, bool b) {
>    return b ? -1 : i;
>    }

>    transform(data.begin(), data.end(), flags.begin(), data.begin(),
>            selector);
>    data.erase(remove(data.begin(), data.end(), -1), data.end());

{ snip unreferenced -mod/jep }

Quote:>In any case, clear the flags.

>    flags = vector<bool>(data.size());

The code snip posed is a simplification from a real app that I was
using to experiment  with.  In reality the data and flag vectors exist
in separate objects and typically contain approx 100,000 elements. The
data  vector is also actually a vector of complex objects. Because of
this I was trying  to avoid the  creation of  a temporary vector
containing both data and flags (ie vector<pair<int, bool> > t)

I had ended up using two steps as you suggest, but had reverted to my
old habits and used a loop to set the data to a known invalid value
and then used erase with a functor to remove the marked data.

So now I can try your approach using transform.

Thanks for the reply - I've learnt something new :-)


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by Siemel Nara » Sun, 18 May 2003 21:08:02



> I have the following data structures:

> vector<int>   data;
> vector<bool> flags;

> My objectives are:

> 1) remove all elements from data where corressponding flag is true
> 2) do it the STL way ;-)

Got my doubts about 2.  Anyway, this seems like it would work

class iterator
{
public:
   class reference;
   typedef std::vector<bool> Remove;
   typedef std::vector<int> Value;
   iterator(Remove::iterator, Value::iterator);
   iterator operator++() { ++d_remove; ++d_value; return *this; }
   const iterator operator++(int) { iterator out=*this; ++*this; return
out; }
   bool operator==(const iterator& that) { return this->d_remove ==
that.d_remove; }
   bool operator!=(const iterator& that) { return this->d_remove !=
that.d_remove; }
   reference operator*() const { return reference(*d_remove,*d_value); }
   operator bool() const { return *d_remove; }
   Value::iterator value_iterator() const { return d_value; }
private:
   Remove::iterator d_remove;
   Value::iterator d_value;

Quote:};

class iterator::reference
{
public:
   reference(bool& remove, int& value);
   void operator=(reference& that)
   {
      this->d_remove = that.d_remove;
      this->d_value = that.d_value;
   }
private:
   bool& d_remove;
   int& d_value;

Quote:};
> so I'm trying to do something like:

> data.erase( remove_if( flags.begin(), flags.end(),
> bind1st(equal_to<bool>(), true)), data.end());

assert(flags.size() == data.size());
data.erase(
   remove_if(
      iterator(flags.begin(),data.begin()),
      iterator(flags.end(),data.end()),
      bind1st(equal_to<bool>(), true)
   ),
   data.end()
);

--
+++++++++++
Siemel Naran


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by Carl Barr » Sun, 18 May 2003 21:20:26




> > vector<int>   data;
> > vector<bool> flags;

> > My objectives are:

> > 1) remove all elements from data where corressponding flag is true
> > 2) do it the STL way ;-)

> To be proper, you would need another structure and some simple things.
> I used the _Selects from g++, but they are available elsewhere.

>     vector<pair<int, bool> > t;
>     transform(data.begin(), data.end(), flags.begin(), back_inserter(t),
>             make_pair<int, bool>);
>     t.erase(remove_if(t.begin(), t.end(),
>             _Select2nd<pair<int, bool> >()), t.end());
>     data.resize(t.size());
>     transform(t.begin(), t.end(), data.begin(),
>             _Select1st<pair<int, bool> >());

> If you can use a special int value such as -1, you could do it in two
> steps.

> int selector (int i, bool b) {
>     return b ? -1 : i;
>     }

>     transform(data.begin(), data.end(), flags.begin(), data.begin(),
>             selector);
>     data.erase(remove(data.begin(), data.end(), -1), data.end());

> If you prefer to violate the rules and use a predicate with
> side-effects,
> the following will do the job.

> template <class Iter, class T>
> struct Picker {
>     Iter& it;
>     Picker (Iter& it) : it(it) {
>         }
>     bool operator() (T const&) {
>         return *it++;
>         }
>     };

>     vector<bool>::const_iterator t(flags.begin());
>     data.erase(remove_if(data.begin(), data.end(),
>             Picker<vector<bool>::const_iterator, int>(t)), data.end());

> In any case, clear the flags.

>     flags = vector<bool>(data.size());

  Does transform require that the op function/functor have no side
effects, if not then using a a struct containing a reference to a vector
of ints and an operator () that push_back's the int arg to this vector,
if the bool is true, and returns anything say int.

// an output iterator to write to nowhere
  template <class T>
  struct null_iterator:public std::iterator<std::output_iterator_tag,
        void,void,void,void>
  {
     null_iterator & operator = (const T &){return *this;}
     null_iterator & operator * () {return *this;}
     null_iterator & operator ++() {return *this;}
  };

  struct chooser
  {
      std::vector<int> &out;
      explicit choooser(std::vector<int> &a):out(a){}
      bool operator () (int x,bool y)
      {
        if(y) out.push_back(x);
        return y;
      }
  }

 ...
  void cleanup(std::vector<int> &data,std::vector<bool> &flags)
  {
  std::vector<int> out;
  std::transform(data.begin(),data.end(),flags.end(),
        null_iterator<bool>(),chooser(out));
  data.swap(out);
  flags = std::vector<bool>(data.size());
  }


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by John Potte » Sun, 18 May 2003 22:41:58



Quote:> I had ended up using two steps as you suggest, but had reverted to my
> old habits and used a loop to set the data to a known invalid value
> and then used erase with a functor to remove the marked data.

The old habbit was well known to you and easy.  Using erase-remove is a
good idea because it is not obvious to the most casual programmer that
it could take n^2 time if done poorly.

Quote:> So now I can try your approach using transform.
> Thanks for the reply - I've learnt something new :-)

Is it better?  I gave three solutions because I had some time on my
hands and found the parallel arrays amusing.  The only important part
was the erase-remove.  The other stuff was just * STL fluff.

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by John Potte » Mon, 19 May 2003 06:11:52




Quote:>   Does transform require that the op function/functor have no side
> effects,

Requires: Op and binary_op shall not have any side effects.

The standard goes out of its way to make sure that implementers may use
any silly code desired by restricting users from doing anything
reasonable.

Your code should work anyway.

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by John Potte » Mon, 19 May 2003 19:38:36





 > > I have the following data structures:

 > > vector<int>   data;
 > > vector<bool> flags;

 > > My objectives are:

 > > 1) remove all elements from data where corressponding flag is true
 > > 2) do it the STL way ;-)

 > Got my doubts about 2.  Anyway, this seems like it would work

 > class iterator

[snip]

The concept is fine but your code took some work to get right.

Since we are amusing ourselves with this little problem, can we come
to any general conclusions?

Could your iterator be generalized to a pair_iterator?  A little more
work to get everything right.  It would need base1 and base2 functions
to return the two internal iterators.  The operator bool applied only
to this problem and would not be there.  Would boost::iterator_adaptors
help?

Would it be better to rewrite the algorithms to take two iterators?  I
did find_if, remove_if and remove_copy_if with less code than the iterator.
I don't think that there are many algorithms to rewrite.

We have unary and binary transform.  How much iterator hackery should be
used to make unary algorithms work on binary data?

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by Carl Barr » Mon, 19 May 2003 19:42:40


 >  ...
 >   void cleanup(std::vector<int> &data,std::vector<bool> &flags)
 >   {
 >   std::vector<int> out;
 >   std::transform(data.begin(),data.end(),flags.end(),
 >         null_iterator<bool>(),chooser(out));
 >   data.swap(out);
 >   flags = std::vector<bool>(data.size());
 >   }

    mental error:: flags.end() above should be flags.begin() above.
  Thanks john  at least it should work:)


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by Siemel Nara » Thu, 22 May 2003 17:55:51


 > On 17 May 2003 08:08:02 -0400, "Siemel Naran"

 > Could your iterator be generalized to a pair_iterator?  A little more
 > work to get everything right.  It would need base1 and base2 functions
 > to return the two internal iterators.  The operator bool applied only
 > to this problem and would not be there.  Would boost::iterator_adaptors
 > help?

I wrote a generic class pair_iterator_t<Iter1,Iter2> and tested it too.  It
is just under 60 lines (that's counting blank lines).  Send me email if you
want to see it.  Don't know much about boost::iterator_adaptors.  Just took
a look at it, but it makes no sense to me!

BTW, std::vector<bool>::reference is a class, not a bool&.

 > Would it be better to rewrite the algorithms to take two iterators?  I
 > did find_if, remove_if and remove_copy_if with less code than the
iterator.
 > I don't think that there are many algorithms to rewrite.

It looks like std::remove_if calls find_if and remove_copy_if, and together
these take between 40 and 50 lines of code.  Not much better than my
pair_iterator of 60 lines (which includes blank lines, lots of typedefs, and
some simple functions defined over multiple lines).

I think on a good compiler the use of pair_iterator should be optimal
because every function is inline so the compiler should be able to optimize
well.

Should we rewrite the algorithms to take two iterators?  No because the
algorithm code is more complex, so it's best to avoid duplicating it.  On
the other hand, the pair_iterator code is conceptually simple.  Also, if we
duplicate the algorithms code, we'll violate the sacrosanct rule that all
code should be factored.

--
+++++++++++
Siemel Naran


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by John Potte » Fri, 23 May 2003 04:12:05





>  > On 17 May 2003 08:08:02 -0400, "Siemel Naran"
>  > Could your iterator be generalized to a pair_iterator?  A little
more
>  > work to get everything right.  It would need base1 and base2
functions
>  > to return the two internal iterators.  The operator bool applied
only
>  > to this problem and would not be there.  Would

boost::iterator_adaptors

Quote:>  > help?
> I wrote a generic class pair_iterator_t<Iter1,Iter2> and tested it
too.  It
> is just under 60 lines (that's counting blank lines).  Send me email
if you
> want to see it.

Thanks for the code.

I think we have different ideas about what a generic pair_iterator is.
I
expect to do everything, not just solve this problem.

   typedef vector<string> Vs;
   typedef deque<double> Dd;
   typedef Vs::iterator VsI;
   typedef Dd::iterator DdI;
   typedef pair_iterator<VsI, VdI> Pi;
   Vs vs;
   Dd dd;
   // ...
   sort(Pi(vs.begin(), dd.begin()), Pi(vs.end(), dd.end()),
           MineComp());

I have 180 lines, all code, which almost works.  Don't forget the const
version.

Quote:> Don't know much about boost::iterator_adaptors.  Just took
> a look at it, but it makes no sense to me!

No comment.  ;-)  You might want to contribute to the thread with
changing
name, currently "When Policies Make Sense".  The subthread with Abrahams
and Dotchevski should be interesting.

Quote:> BTW, std::vector<bool>::reference is a class, not a bool&.

Yes.  I don't see your point.  I must be missing something.

Quote:>  > Would it be better to rewrite the algorithms to take two iterators?
I
>  > did find_if, remove_if and remove_copy_if with less code than the
>  > iterator.  I don't think that there are many algorithms to rewrite.
> It looks like std::remove_if calls find_if and remove_copy_if, and
together
> these take between 40 and 50 lines of code.  Not much better than my
> pair_iterator of 60 lines (which includes blank lines, lots of
typedefs, and
> some simple functions defined over multiple lines).

Mine was 30 lines; however, if we generalize, all algorithms require a
rewrite.  I have no desire to rewrite sort even if it is trivial.

Pair_iterator should generalize like pair.

   typedef pair_iterator<Pi, Pi> Qi;

Now all algorithms work on all parallel containers.

John


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

Help with STL std::remove_if

Post by Dhru » Tue, 27 May 2003 23:59:39




Quote:> > I have the following data structures:

> > vector<int>   data;
> > vector<bool> flags;

> > My objectives are:

> > 1) remove all elements from data where corressponding flag is true
> > 2) do it the STL way ;-)

> > so I'm trying to do something like:

> > data.erase( remove_if( flags.begin(), flags.end(),
> > bind1st(equal_to<bool>(), true)), data.end());

> > but it's not quite right. Can anyone point me in the right

direction?
Try this:

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

template <class t, class c>
struct aaa /*incr_on_call_and_erase_form_t*/ {
private:
  //  t& t_data;
  t& t_data;
  typename t::iterator iter;

public:

  aaa (t& _t): t_data(_t) /*, c_data(_c)*/ {
  iter = _t.begin ();
  }
  void operator() (const c& _condition)
  {
    if (_condition) iter = t_data.erase (iter);
    else ++iter;

  }

Quote:};

int main ()
{
  vector<int> data;
  vector<bool> flag;

  //add equal amounts of elements to data, and flag.

  data.push_back (34);
  data.push_back (23);
  data.push_back (56);
  data.push_back (79);
  data.push_back (9);

  flag.push_back (0);
  flag.push_back (1);
  flag.push_back (0);
  flag.push_back (1);
  flag.push_back (0);

  for_each (flag.begin(), flag.end (), aaa<vector<int>, bool> (data));

  for (vector<int>::iterator vii = data.begin(); vii != data.end ();
++vii)
    std::cout<<*vii<<"\t";

Quote:}


      [ about comp.lang.c++.moderated. First time posters: do this! ]
 
 
 

1. problems with std::remove_if()

While trying to use the algorithm std::remove_if (), I get the following
compile error with one compiler:
Error   : using implicit copy assigment for class with const or reference
member ('std::pair<const std::basic_string<char, std::char_traits<char>,
std::allocator<char>>, a *>')
hello.cpp line 51   }

It compiles fine with another compiler.
Am I doing something wrong?
Thanks in advance

#include <map>
#include <string>
#include <algorithm>

struct a
{
 std::string s1;
 std::string s2;

 bool operator == (const a &rhs) const
 {
  return (s1 == rhs.s1) && (s2 == rhs.s2);
 }

typedef std::pair <std::string, a> MYMAPPING;

struct Predicate
{
 bool operator () (const std::pair<std::string, a*> &rhs) const
 {
  return (lookup.first == rhs.first) && (lookup.second == *(rhs.second));
 }

 Predicate (MYMAPPING m): lookup(m) { }

private:

 MYMAPPING lookup;

typedef std::multimap <std::string, a*> MYMAP;
typedef MYMAP::iterator MYITER;

int main ()
{
 MYMAP m1, m2;

 // remove every element in m2 from m1

 MYITER iter = m2.begin ();

 while (iter != m2.end())
 {
  MYMAPPING to_remove (iter->first, *(iter->second));
  std::remove_if (m1.begin (), m1.end (), Predicate(to_remove));
 }

 return 0;

2. Pctel HSP56 MR

3. std::remove_if and pair-associative containers

4. file path to attachment

5. STL list::remove_if unary predicate

6. Determine VMS version numbers on LAN

7. STL: list::remove_if()

8. Corrupt GFX Icon with my AMIAG... HELP!

9. STL (specification) BUG: lost function object state in remove_if()

10. std::getline(std::istream &, std::string &) and std::ifstream (and using decl.)

11. Need help with a std::vector in a std::map

12. Why not std::map<std::string, std::string[] > ?

13. Defect Report: std::min and std::max not inheriting std::binary_function