Алгоритм STL для обработки первых N элементов, соответствующих условию - PullRequest
2 голосов
/ 01 ноября 2019

У меня есть кусок кода, который перебирает вектор координат. Затем я хочу использовать первые N координат из вектора, которые соответствуют условию. Подход (упрощенный):

Matrix image;
int maxCount = N;
std::vector<Point> coordinates(sizeof >> maxCount);
std::vector<SomeClass> filtered;
filtered.reserve(maxCount);
for (const auto& coordinate : coordinates)
    {
        if (image.at(coordinate) != 255)
        {
            continue;
        }

        filtered.emplace_back(coordinate, ...);

        // end when we have enought points
        if (filtered.size() == maxCount)
        {
            break;
        }
    }

Я бы хотел избежать цикла for и использовать библиотеку STL. Примерно так:

for_each_n_if(begin(v), N, [&](Point p){ 
 if(cond) {
      otherVec.emplace_back(p,...);
      return true; // help counter is incremented
 } else {return false;}});

Есть ли какая-нибудь функция, которая может сделать это в stl? (я проверил, просто подумал, пропустил ли я что-то не столь очевидное)

Ответы [ 2 ]

2 голосов
/ 01 ноября 2019

Большинство алгоритмов STL фокусируются на одной конкретной задаче, они плохо сочетаются - вот почему мы получим диапазоны в первую очередь. До этого вам либо придется

  1. разделить ваше намерение на несколько вызовов алгоритма,
  2. написать конкретный алгоритм для вашего варианта использования
  3. продолжить придерживаться ручного цикла (в конце концов, они могут быть довольно читабельными) или
  4. использовать одну из доступных библиотек диапазонов.

Одно предложение для 2., конкретный алгоритм:

template <class InputIt, class Size, class OutputIt, class Pred, class Fct>
auto transform_n_if(InputIt first, InputIt last, Size count, OutputIt dest,
    Pred pred, Fct transform)
{
   Size n(0);

   while (first != last && n !=count) {
      if (pred(*first)) {
         *dest++ = transform(*first);
         ++n;
      }

      ++first;
   }

   return dest;
}

, который можно вызывать так:

std::vector<Point> coordinates(someSize);
std::vector<SomeClass> filtered;

transform_n_if(coordinates.cbegin(), coordinates.cend(), 42, std::back_inserter(filtered),
      [](const Point& p){ return /* your condition here... */ true; },
      [](const Point& p){ return /* your transformation here... */ SomeClass(p); });
1 голос
/ 01 ноября 2019

Вы можете использовать std::all_of и возвращать false из предиката, когда хотите остановить:

std::all_of(coordinates.begin(), coordinates.end(),
            [&](const auto& coordinate)
            {
               if (image.at(coordinate) == 255)
                  filtered.emplace_back(coordinate, ...);
               return filtered.size() < maxCount;
            });

Просто я не уверен, что это более читабельно, чем цикл.

...