3

Given a vector such as this:

struct product {
    float price;
    float shipping;
};

vector<product> products;

how can I remove all the products from the vector apart from the one with the largest shipping to price ratio?

I tried keeping an iterator to the highest one found so far...

vector<product>::iterator it = products.begin();
vector<product>::iterator largest = products.begin();

while (it != products.end())
{
    if (it->shipping / it->price > largest->shipping / largest->price)
    {
        products.erase(largest);
        largest = it;
        ++it;
    }
    else
    {
        it = products.erase(it);
    }
}

This is all well and good but it fails if the first element in the vector has the highest ratio (it gets deleted). I could get around the problem (I think) if largest was uninitialized and then checking for that in the if statement, but there is no real way of doing this from what I can tell (How to check if the iterator is initialized?).

Any suggestions?

Community
  • 1
  • 1
zoran119
  • 10,657
  • 12
  • 46
  • 88

3 Answers3

4
 vector<product> products;
 //populate products

 products.erase(
      products.begin(),
      std::max_element(
          product.begin(), 
          producted.end()
      )
 );
 products.resize(1u);

This assume you have a suitable operator< for your type, if not, make a comparison function and provide it as the third param to max_element.

EDIT:

This work also, in this case, instead of explicitly find the element and delete the element either side, it will sort to find 1 elemnt, then we can do one erase.

 vector<product> products;
 //populate products
 std::nth_element(
      products.begin(), 
      products.begin()+1, 
      products.end(), 
      std::greater<product>()
 );
 products.resize(1u);
111111
  • 15,686
  • 6
  • 47
  • 62
0

Just rewrite the code to only make one single deletion:

std::vector<product>::iterator largest = products.begin();

for (std::vector<product>::iterator it = products.begin(); it != products.end(); ++it)
{
    if (...) { largest = it; }
}

products.erase(it);
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • say that my vector has 10 elements. how will one single deletion remove 9 of them (there is only one with the largest ratio which should be left)? – zoran119 Nov 07 '12 at 23:31
  • @zoran119: You need two passes. Determine the *value* of the largest ratio first, and then delete all those elements. Use `std::remove_if` for that. – Kerrek SB Nov 08 '12 at 03:33
0

You could define largest as the first element and start iteration from the second element, just as followings:

bool operator < (const struct product& p1, const struct product& p2)
{
   return p1.price/p1.shipping < p2.price/p2.shipping;
}

vector<product>::iterator largest = products.begin();
vector<product>::iterator it = products.begin();
++it;

while (it != products.end())
{
    if (*largest < *it)
    {
        products.erase(largest);
        largest = it;
        ++it;
    }
    else
    {
        it = products.erase(it);
    }
 }

But there is a bug here, after products.erase(largest) is called, it will be invalidated, so you'd better take the approach other suggested here.

Zhi Wang
  • 1,138
  • 4
  • 20
  • 34