Как взять определенные элементы из одного контейнера и вставить их преобразование в другой контейнер? - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть vector<int*>, и я хочу поместить все указанные элементы в vector<int>. Все непоказанные элементы установлены на nullptr.

Я думал о том, чтобы сделать что-то вроде этого:

vector<int> copy_valid_elements(vector<int*> piv)
{
 vector<int> result;
 result.reserve(piv.size());
 auto end_it = std::remove_if(piv.begin(), piv.end(), [](int* p) { return !p; });
 std::transform(piv.begin(), end_it, back_inserter(result), [](int* p) { return *p; });
 return result;
}

Но это потребовало бы перемещения элементов в массиве без необходимости. Я мог бы сделать цикл for, но я надеялся, что существует алгоритм, который представляет собой нечто среднее между std::copy_if и std::transform. Есть ли такой зверь?

1 Ответ

0 голосов
/ 06 сентября 2018

Вот шаблон функции, который применяет необязательное преобразование с двумя предикатами: один для фильтрации и один для фактического отображения.

template <class InpIt, class OutIt, class Pred, class Fct>
OutIt transform_if(InpIt first, InpIt last, OutIt dest, Pred pred, Fct transform)
{
   while (first != last) {
      if (pred(*first))
         *dest++ = transform(*first);

      ++first;
   }

   return dest;
}

Вы можете назвать это так

int n1 = 1, n2 = 2, n3 = 3;

std::vector<int*> input{&n1, nullptr, nullptr, nullptr, &n2, &n3, nullptr};
std::vector<int> result;

transform_if(input.cbegin(), input.cend(), std::back_inserter(result),
    [](auto *i){ return i != nullptr; }, [](auto *i){ return *i; });

Другой возможностью является использование библиотеки диапазонов, так как одной из их основных целей является простое составление алгоритмов. С диапазоном усиления:

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>

using namespace boost::adaptors;

/* Variable setup as above... */

boost::copy(input | filtered([](auto *i){ return i != nullptr; }) | indirected,
    std::back_inserter(result));
...