从另一个向量的规则间隔元素创建子向量

时间:2011-12-06 18:23:03

标签: c++ vector

非常简单的问题:有没有一种聪明的方法可以使用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 个答案:

答案 0 :(得分:5)

作为一般解决方案,您可以定义stride iterator。如果您使用Boost.Range,那么它已经是strided range adaptor

示例:

#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 :(得分:1)

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 而不是单独的仿函数,您可以使用内联lambda,如此

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;
}

答案 2 :(得分:1)

(创建另一个答案,因为这是一种不同的方法。)

如果你只想push_back另一个容器的strided slice,并且不想在其他任何地方使用那个lst[a:b:c]概念,那么编写一个通用的copy函数可能更容易:< / p>

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;
      }
   }
}

Usage

#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, ", "));
}

答案 3 :(得分:0)

标准库中不存在专门用于此任务的任何内容。

以下是我自己的通用实现。随机访问迭代器和其他输入迭代器有一个单独的实现。

#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