Adrian
Adrian

Reputation: 11

Methods with certain functions

Is there any way to write these two class methods, without using loops, lambda functions, and other additional functions? I only want to use the functions and functors from libraries algorithm and functional. I have tried to use while loop and recursion to fugure something out, but still couldn't solve this. I didn't want to post the whole code since it is too long.

(I don't have to use these libraries for << operator, if there is a way to solve this without them, and min and max are lists) My main goal is not using loops, lambda functions and any additional functions outside the two libraries. EraseNegativeTemperatures is the method which should only erase the registered pairs of temperatures where both of them are negative (I wrote the method in the part which I didn't post, and that method makes pairs where one temperature is from min and the other one from max)

Operator << outputs all the registered temperatures, the min ones in one row and the max ones in the second row; the temperatures in one row are separates by space.

void Temperatures::EraseNegativeTemperatures() {
  for (auto it = max.begin(); it != max.end(); it++) {
    if (*it < 0) {
      auto it1 = it;
      auto it2 = min.begin();
      while (it1 != max.begin()) {
        it2++;
        it1--;
      }
      min.erase(it2);
      it = max.erase(it);
    }
  }
  // std::remove_if(min.begin(), min.end(), std::bind(std::less<int>(),
            max.begin() + std::placeholders::_1 - min.begin(), 0));
}

// second method
std::ostream &operator<<(std::ostream &flow, const Temperatures &t) {
  std::for_each(t.min.begin(), t.min.end(),
                [&flow](int x) { flow << x << " "; });
  flow << std::endl;
  std::for_each(t.max.begin(), t.max.end(),
                [&flow](int x) { flow << x << " "; });
  flow << std::endl;
  return flow;
}

Upvotes: 0

Views: 106

Answers (2)

Aconcagua
Aconcagua

Reputation: 25526

At first it might be simpler to erase from both lists separately; the following (disallowed) lambda solution will be the starting point:

auto current = max.begin();
min.erase(
    remove_if(
        min.begin(), min.end(),
        [&current] (int /* ignored! */) { return *current++ < 0; }
    ),
    min.end()
);

This will remove all those elements from the min list that have a corresponding negative value in the max list. Afterwards you can remove the negative values from the max list with an expression you have already found:

max.erase(
    remove_if(
        max.begin(), max.end(),
        std::bind(std::less<int>(), std::placeholders::_1, 0)
    ),
    max.end()
);

The tricky part is now to re-build the lambda with standard library means only.

So we will need the operators above available as ordinary functions so that we can bind to them:

auto dereference = &std::list<int>::iterator::operator*;
auto postIncrement = static_cast<
        std::list<int>::iterator (std::list<int>::iterator::*)(int)
    >(
        &std::list<int>::iterator::operator++
    );

The static_cast for getting the second operator is necessary to distinguish the post-increment operator from the pre-increment operator.

Now we need to bind everything to the less-than operator:

auto lt0 = std::bind(
        std::less<int>(),
        std::bind(dereference, std::bind(postIncrement, std::ref(current), 0)),
        0
);

Note the creation of a reference to the iterator! The resulting functor we now can use to erase from min list:

min.erase(remove_if(min.begin(), min.end(), lt0), min.end());

Pretty similarly we can create the functor for outputting the arrays; at first we need the operators available; note that one of is a member function, the other one not:

auto outInt = static_cast<std::ostream& (std::ostream::*)(int)>(
    &std::ostream::operator<<
);
auto outChar = static_cast<std::ostream& (*)(std::ostream&, char)>(
    &std::operator<<
);

Now we can again bind everything together:

auto out = std::bind(
    outChar,
    std::bind(outInt, std::ref(flow), std::placeholders::_1),
    ' '
);

std::for_each(t.min.begin(), t.min.end(), out);
flow << std::endl;
std::for_each(t.max.begin(), t.max.end(), out);
flow << std::endl;

Upvotes: 1

Surt
Surt

Reputation: 16099

As far as I can see you erase a temperature from each of min and max vector which are reverse of each other.

Added a test if the min temp is also negative.

Totally untested code

void Temperatures::EraseNegativeTemperatures() {
  for (auto it = max.begin(); it != max.end(); it++) {
    if (*it < 0) {
      auto diff = std::distance(max.begin(), it);
      
      if (*(min.rend()+diff) < 0) {
        min.erase(min.rend()+diff); // reverse of max
        it = max.erase(it);
      }
    }
  }

Upvotes: 1

Related Questions