Создать подвектор из регулярно расположенных элементов другого вектора - PullRequest
3 голосов
/ 06 декабря 2011

Очень простой вопрос: существует ли разумный способ создания субвектора из регулярно расположенных элементов другого вектора с помощью STL?

Короче говоря, возможно ли написать следующий код с алгоритмом STL:

int inc = 2;
std::vector<double> v_origin;
std::vector<double> v_dest;

for (int i = 0; i < v_origin.size(); i+= inc)
    v_dest.push_back(v_origin[i]);

Как я бы написал в Matlab или Python что-то вроде:

v_dest = v_origin[0:inc:end];

Ответы [ 4 ]

5 голосов
/ 06 декабря 2011

Как общее решение, вы можете определить итератор шага . Если вы используете Boost.Range, то он уже как strided адаптер диапазона .

Пример:

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

int main()
{
    int inc = 2;
    std::vector<double> v_origin;
    std::vector<double> v_dest;

    for (int i = 0; i < 10; ++ i)
        v_origin.push_back(i);

    boost::copy(v_origin | boost::adaptors::strided(2),
                std::back_inserter(v_dest));
    // ^ In Python:    v_dest[] = v_origin[::2]

    boost::copy(v_dest, std::ostream_iterator<double>(std::cout, ", "));
}
1 голос
/ 06 декабря 2011

(Создание другого ответа, поскольку это другой подход.)

Если вы просто хотите отодвинуть пошаговый фрагмент другого контейнера и не собираетесь использовать эту концепцию lst[a:b:c] где-либо еще, возможно, этопроще написать общую copy -подобную функцию:

template <typename InputIterator, typename OutputIterator>
void copy_strided(InputIterator begin, InputIterator end,
                  OutputIterator result, size_t stride)
{
   assert(stride >= 1);

   for (size_t i = stride; begin != end; ++ i, ++ begin)
   {
      if (i == stride)
      {
         *result = *begin;
         ++ result;
         i = 0;
      }
   }
}

Использование :

#include <vector>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <iterator>

int main()
{
    int inc = 2;
    std::vector<double> v_origin;
    std::vector<double> v_dest;

    for (int i = 0; i < 10; ++ i)
        v_origin.push_back(i);

    copy_strided(v_origin.begin(), v_origin.end(), std::back_inserter(v_dest), inc);

    std::copy(v_dest.begin(), v_dest.end(), std::ostream_iterator<double>(std::cout, ", "));
}
1 голос
/ 06 декабря 2011
struct RemoveNth
{
    RemoveNth(int incin)
    {
        count = 0;
        inc = incin;
    }

    bool operator()(double x )
    {
        return count++ % inc == 0;
    }

    int count;
    int inc;
};

int main()
{

    int inc = 2;
    std::vector<double> v_origin;
    std::vector<double> v_dest;

    for ( int i = 0 ; i < 100; ++i )
        v_origin.push_back( i );

    v_dest  = v_origin;
    RemoveNth helper(3);
    std::vector<double>::iterator newend = 
         std::remove_if (v_dest.begin() , v_dest.end(), helper); 
    v_dest.erase( newend , v_dest.end() );

    return 0;
}

Нечто подобное может работать.

В C ++ 11 вы можете использовать std :: copy_if и вместо отдельного функтора вы можете использовать встроенные лямбда-выражения, например,

template<typename T, typename U>
void copynth( T begin , T end , U dest , int n )
{
    int count = 0;
    std::copy_if( begin , end , dest ,
        [&count,n]( double x )
    {
        return count++ % n == 0;
    });
}

int main()
{

    int inc = 2;
    std::vector<double> v_origin;
    std::vector<double> v_dest;

    for ( int i = 0 ; i < 100; ++i )
        v_origin.push_back( i );

    int count = 0;
    copynth( v_origin.begin() , v_origin.end() , std::back_inserter(v_dest) , 4);

    return 0;
}
0 голосов
/ 06 декабря 2011

В стандартной библиотеке нет ничего, специально предназначенного для этой задачи.

Ниже моя собственная общая реализация. Существует отдельная реализация для итератора произвольного доступа и для других входных итераторов.

#include <iterator>

namespace detail {
template <class SourceIter, class OutIter>
void strided_copy_aux(SourceIter from, SourceIter to, OutIter out, unsigned step, std::random_access_iterator_tag)
{
    SourceIter end = (to - from) / step * step + from;
    for (; from < end; from += step ) {
        *out = *from;
    }
    if (end < to) {
        *out = *end;
    }
}

template <class SourceIter, class OutIter>
void strided_copy_aux(SourceIter from, SourceIter to, OutIter out, unsigned step, std::input_iterator_tag)
{
    while (from != to) {
        *out = *from;
        for (unsigned i = 0; i != step; ++i) {
            ++from;
            if (from == to) break;
        }
    }
}
}

template <class SourceIter, class OutIter>
void strided_copy(SourceIter from, SourceIter to, OutIter out, unsigned step)
{
    detail::strided_copy_aux(from, to, out, step, typename std::iterator_traits<SourceIter>::iterator_category());
}

Пример использования: http://ideone.com/1Wmq3

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...