2

For a C++ project, I have a vector with custom objects that have a method getX() to get their x value.

I have a method that needs to loop over all elements where property x is between startX and endX.

What is the correct way to loop over those items?

Currently I have:

int startX = 20;
int endX = 30
for(SomeClass x: someObject->getObjects())
{
  if(x->getX() > startX && x->getX() < endX)
  {
    //do something
  }
}

It works fine, but I remember from an old C++ lesson that there was a method that loops over the elements more efficiently.

I remember something like:

int startX = 20;
int endX = 30
for(SomeClass x : find(someObject->getObjects(), x, x->getX() > startX && x->getX() < endX)
{      
    //do something
}

Where I only iterate over the elements that I need and the check is not inside of the loop anymore.

edit: I changed the qt foreach loop to a for loop to avoid discussion about that part.

Sven van den Boogaart
  • 11,833
  • 21
  • 86
  • 169
  • 1
    What is `foreach`? – Evg Jan 10 '20 at 08:44
  • 1
    Seems fine. You can store `x->getX()` if that one is a non trivial getter. With range library, you might have more natural syntax. – Jarod42 Jan 10 '20 at 08:44
  • @evg its a method from qglobal (qt) – Sven van den Boogaart Jan 10 '20 at 08:45
  • 3
    @SvenvandenBoogaart and it's deprecated since 2012 – Moia Jan 10 '20 at 08:46
  • 3
    -> `for(Element x : someObject->getObject())` – Jarod42 Jan 10 '20 at 08:49
  • You might find this useful about range based for loop: https://stackoverflow.com/questions/15927033/what-is-the-correct-way-of-using-c11s-range-based-for – jignatius Jan 10 '20 at 08:50
  • C++ has it's own range based loop now `for (Element /*const*/& : someObject->getObject())`. Efficiency is hard to determine and may end up being different between compilers and machines if only by a tiny amount. I'd worry about then if their performance becomes a problem on a target machine but 99.9% of the time, there's gonna be better things to spend your time on for buying back performance. – George Jan 10 '20 at 08:57
  • @Moia what is deprecated? the foreach is still in the documentation: https://doc.qt.io/qt-5/containers.html#the-foreach-keyword – Sven van den Boogaart Jan 10 '20 at 09:15
  • 1
    @SvenvandenBoogaart https://doc.qt.io/qt-5/qtglobal.html#foreach says it's deprecated and may be removed in the future. But I did not manage to find that without serious effort. – Max Langhof Jan 10 '20 at 09:22
  • @ Max Langhof it dosnt say it is deprecated yet it will be deprecated in the future, but thanks anyway I will change it to for. – Sven van den Boogaart Jan 10 '20 at 09:27
  • 1
    Is the array sorted? If not, on an abstract level, there will inevitably be the same memory access and comparisons required like in your first solution. A performance improvement is quite unlikely and this code is the right amount of verbose as it is, if you ask me. Separating the checks into some sort of lambda, would make it less readable... – AlexGeorg Jan 10 '20 at 09:41
  • [Not yet deprecated, but deprecation in work](https://codereview.qt-project.org/c/qt/qtbase/+/147363) – user1810087 Jan 10 '20 at 09:45
  • By the way, if you have such searches often and performance is critical, you could do what some game engines do and use spatial search algorithms on spatial data structures! For example kd-trees. – AlexGeorg Jan 10 '20 at 09:48

2 Answers2

4

Are you thinking of (a precursor to) std::ranges::filter?

int startX = 20;
int endX = 30;
auto inrange = [startX, endX](auto x){ return x->getX() > startX && x->getX() < endX; }
for(SomeClass x: std::ranges::filter(someObject->getObjects(), inrange))
{
    //do something
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
0

assuming the condition x->getX() > startX && x->getX() < endX is correct, the you can do:

std::vector<Foo> foo = {foo1, foo2, foo3};
std::vector<Foo> bar;

// copy only positive numbers:
std::copy_if (foo.begin(), foo.end(), std::back_inserter(bar), [](Foo x){return x.getX() > startX && x.getX() < endX;} );
ΦXocę 웃 Пepeúpa ツ
  • 47,427
  • 17
  • 69
  • 97