sort using boost::bind
Asked Answered
S

3

1
bool pred(int k, int l, int num1, int num2)  
{
return (num1 < num2);
}

int main()
{
   vector <int> nums;
   for (int i=50; i > 0; --i)
   {
      nums.push_back(i);
   }
   std::sort (nums.begin(), nums.end(), boost::bind(&pred, 5, 45));
}

I am a boost newbie. I was learning to use boost::bind and I wanted to sort a vector of integers and get rid of all those elements in the vector that are greater than 45 and less than 5. Had a hard time doing it. Would be great if anyone could help me do it?

The reason I am facing problem is because I am trying to get rid of a vector element while iterating through the vector to sort it. I know it would be much easier if i sort it first and then remove elements from it. But I want to do it this way. Any help is appreciated.

Susceptive answered 4/11, 2009 at 22:46 Comment(0)
L
4

You can't do that from sort.

Remove the elements before or after sort.

bool outOfRange(int low, int high, int num) {
    return low > num || num > high;
}

...

    nums.erase(
            std::remove_if(nums.begin(), nums.end(),
                    boost::bind(&outOfRange, 5, 45, _1)),
            nums.end()
        );

Though you really don't need boost::bind at all. Heck, we can make it a bit more generic too:

template<typename T, class cmp = std::less<T> >
struct outOfRange : std::unary_function<T, bool> {
    outOfRange(const T &low, const T &high) : low(low), high(high) {}
    bool operator()(const T &val) { return cmp()(val, low) || cmp()(high, val); }
    const T &low, &high;
}

...

    nums.erase(
            std::erase_if(nums.begin(), nums.end(), outOfRange<int>(5, 45)),
            nums.end()
        );
Leeann answered 4/11, 2009 at 23:5 Comment(3)
I think you need to include a placeholder in you boost::bind expression: boost::bind(&outOfRange, 5, 45, _1)Soutor
Yeah, I do, oops. I'll fix that, and actually maybe simplify things at the same time.Leeann
boost::lambda is a lot more useful than boost::bind in cases like this: std::erase_if(nums.begin(), nums.end(), _1 < 5 || _1 > 45); The error messages if you get something wrong are scary stuff, though!Heavyhearted
S
2

There many ways to do it. The easiest is to first remove all unwanted elements and then sort:

bool outsideRange(int num, int min, int max)  
{
  return (num < min) || (num > max);
}

nums.erase(std::remove_if(nums.begin(),nums.end(),boost::bind(&outsideRange,_1,5,45) ) ); // See comments about remove-erase idiom.
std::sort(nums.begin(),nums.end());

Note that when using boost bind you need to include the placeholder (_1), that tells it which argument is the one being iterated over.

If you prefer to to it in one step, you could conditionally copy all your ints to a multiset, which sort the items for you:

bool outideRange(int num, int min, int max)  
{
    return (num < min) || (num > max);
}

std::multiset numsInSet;
std::remove_copy_if(
   nums.begin(),
   nums.end(),
   std::inserter(numsInSet,numsInSet.begin()), 
   boost::bind(&outideRange,_1,5,45) );
Soutor answered 4/11, 2009 at 23:27 Comment(3)
Heh, you made the same mistake I made at first: remove_if doesn't actually remove anything :)Leeann
Yup... look up the erase-remove idiom (en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Erase-Remove)Microwave
Oops, forgot about that. Updated the example accordingly. Thanks!Soutor
W
0

Your idea is not quite possible as std::sort can only affect the ordering of your vector and cannot modify the values themself.

The closet thing I can think of that would approximate what you want is to have all the valid values (those that are >= 5 and <= 45) come before invalid values but have both the valid and invalid value sorted.

bool pred(int min, int max, int num1, int num2)
{
    bool num1_valid = (num1 >= min) && (num1 <= max);
    bool num2_valid = (num2 >= min) && (num2 <= max);

    if (num1_valid == num2_valid)
    {
        return num1 < num2; 
    }
    else
    {
        return num1_valid;
    }
}
Weigle answered 4/11, 2009 at 23:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.