Можем ли мы получить итератор, который фильтрует вектор из предиката в C ++? - PullRequest
0 голосов
/ 10 июня 2019

Можно ли получить итератор для вектора, который фильтрует некоторый элемент с помощью предиката, то есть показывает представление вектора?

Я думаю, remove_if делает что-то подобное, но я не нашел, могу ли я использовать его так, как хочу или нет.

Что-то вроде:

auto it = filter(vec.begin(), vec.end(), predicate);
// I can reuse the iterator like:
for (auto i = it; i != vec.end(); i++)
    // ...

Редактировать: (немного больше контекста, чтобы получить лучший ответ) Я выполняю много запросов в базе данных sqlite данных журнала, чтобы напечатать отчет.

На данный момент показатели не очень хорошие из-за количества запросов. Я полагаю, что запрос к базе данных и сохранение результата в векторе интеллектуальных указателей (unique_ptr, если возможно), тогда запрос к вектору с чистым C ++ может быть быстрее.

Использование copy_if является хорошим способом выполнения запросов, но мне не нужно копировать все, и в конце это может стоить слишком дорого (не уверен насчет этого), я должен был упомянуть, что данные неизменны в моем случае.

Ответы [ 2 ]

2 голосов
/ 10 июня 2019

Как упомянуто в комментариях @ Jarod42, одно решение будет использовать диапазоны:

#include <algorithm>
#include <iostream>
#include <vector>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>

int main()
{

   std::vector<int> numbers = { 1, 2, 3 ,4, 5 };
   auto predicate = [](int& n){ return n % 2 == 0; };
   auto evenNumbers = numbers | ranges::view::filter(predicate);
   auto result = numbers | ranges::view::filter(predicate) 
                         | ranges::view::transform([](int n) { return n * 2; });
   for (int n : evenNumbers)
   {
      std::cout << n << ' ';
   }
   std::cout << '\n';
      for (int n : result)
   {
      std::cout << n << ' ';
   }
}

evenNumbers - это адаптер представления диапазона, который придерживается диапазона numbers и меняет способ его итерации.

result - это диапазоны чисел, которые были отфильтрованы в предикате, а затем применены функции.

см. Компиляцию в compiler-explorer

кредит: fluentcpp

1 голос
/ 10 июня 2019

Ваш вопрос

Можем ли мы получить итератор, который фильтрует вектор из предиката в C ++?

в том смысле, в каком вас спрашивают, можно ответить только с помощью: Нет. На данный момент нет (C ++ 17). Согласно вашему требованию итератор должен будет хранить предикат и проверять его для каждой модификации позиции или для всего разыменовывающего материала. Т.е. перед любой разыменовкой нужно будет проверить предикат. Потому что другой код может изменить ваш std :: vector. Итератор должен постоянно проверять предикат. Также стандартные функции, такие как начало, конец, расстояние, были бы довольно сложными.

Таким образом, вы можете создать свой собственный итератор, производный от существующего итератора. Сохраните предикат и перегрузите большинство функций, чтобы позаботиться о предикате. Очень, очень сложно, много работы и, возможно, нет, то, что вы хотите иметь. Это был бы единственный способ получить точную требуемую функциональность.

Для обходных путей существует множество других возможных решений. Peolple покажет вам здесь.

Но если я прочитаю ваше заявление

«показывающий вид вектора»

тогда жизнь станет легче. Вы можете легко создать представление вектора, условно скопировав его с помощью std :: copy_if, как написано oblivion . Это, на мой взгляд, лучший ответ. Это не разрушительно. Но это снимок, а не исходные данные. Итак, это только для чтения. Кроме того, он не учитывает изменения исходного std :: vector после создания снимка.

Второй вариант, комбинация std :: remove_if и std :: erase, уничтожит исходные данные. Или лучше сказать, это сделает недействительными отфильтрованные данные. Вы также можете std :: copy_if ненужные данные в резервную область, std :: remove_if их, и в конце добавить их снова в вектор.

Все эти методы являются критическими, если исходные данные будут изменены.

Может быть, для вас лучше всего использовать стандартный std :: copy_if. Затем вы должны вернуть итератор копирования и работать с этим.

#include <iostream>
#include <vector>
#include <algorithm>

int main()
{
    std::vector<int> testVector{ 1,2,3,4,5,6,7 };   // Test data
    std::vector<int> testVectorView{};              // The view

    // Create predicate
    auto predForEvenNumbers = [](const int& i) -> bool { return (i % 2 == 0);  };
    // And filter. Take a snapshot
    std::copy_if(testVector.begin(), testVector.end(), std::back_inserter(testVectorView), predForEvenNumbers);

    // Show example result
    std::vector<int>::iterator iter = testVectorView.begin();
    std::cout << *iter << '\n';

    return 0;
}

Пожалуйста, обратите внимание. Для больших std :: vectors это станет очень дорогим решением. , .

...