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