在 C++ 中交织/解交织 3 个向量STL

发布于 2024-09-17 05:57:49 字数 2235 浏览 2 评论 0原文

我正在尝试将三个信号波形组合成一个交错波形。我需要知道在 C++ STL 中执行此操作的最佳方法。更好的解决方案将尽可能多地使用 C++ STL 样式,避免冗余代码等。是否有一些 STL“元组”类型类可以为我做到这一点?我始终需要连续存储以向后兼容其他代码(因此,矢量)。最好的解决方案应该是正确且易于理解的。空间和速度不如正确性易于理解那么重要。

输出波形必须按如下顺序排序:第一个通道的第一个样本、第二个通道的第一个样本、第三个通道的第一个样本,然后继续每个通道的第二个样本,并对所有样本重复。我知道所有三个输入波形都具有相同数量的样本。

在 Matlab 中,我会这样做:

function outputWaveform=Interleave3(a, b, c)
outputWaveform=zeros([1 3*length(a)]);
outputWaveform(1:3:end)=a(:);
outputWaveform(2:3:end)=b(:);
outputWaveform(3:3:end)=c(:);

这是我的第一次 C++ STL 尝试:

typedef vector<double>  dVector;
typedef vector<double>::iterator  dVectorIT;
dVector Interleave3(dVector a, dVector b, dVector c)
{
    dVector result(0, 3*a.size());
    dVectorIT aIT=a.begin(), bIT=b.begin(), cIT=c.begin(), rIT=result.begin();
    for(; aIT != a.end(); ++aIT, ++bIT, ++cIT)
    {
        *rIT++=*aIT;
        *rIT++=*bIT;
        *rIT++=*cIT;
    }
    return  result;
}

它有效,但是有更好的方法吗?我希望有一些聪明的方法可以用 transform() 在一行中完成它。您可以将 b 附加到 a,然后将 c 附加到 a,然后将临时“a1a2a3...-b1b2b3...-c1c2c3...”向量转换为“a1b1c1a2b2c2a3b3c3...”吗?

额外问题:我还需要逆运算(将 3*N 个样本的输出波形拆分为每个 N 个样本的 3 个向量)。 Matlab 解决方案非常简单:

function [a, b, c]=Deinterleave3(outputWaveform)
a=outputWaveform(1:3:end);
b=outputWaveform(2:3:end);
c=outputWaveform(3:3:end);

C++ STL 看起来相当尴尬,我敢打赌有比这更好的方法:

typedef vector<double>  dVector;
typedef vector<double>::iterator  dVectorIT;
void Deinterleave3(dVector outputWaveform, dVector &a, dVector &b, dVector &c)
{
    ASSERT( !(outputWaveform.size()%3) );
    a.clear(); b.clear(); c.clear();
    dVectorIT oIT=outputWaveform.begin();
    for(; oIT != outputWaveform.end(); )
    {
        a.push_back( *oIT++ );
        b.push_back( *oIT++ );
        c.push_back( *oIT++ );
    }
}

是否有 transform()back_inserter() 哪个会执行逆操作?同样,使用临时向量是可以接受的。

Boost 有一个“zip 迭代器”,但我不知道它是否会执行交织或解交织操作。

编辑:修复了缺失的尖括号(<>)。 HTML 过滤器吞噬了它们!另外,我对如何使用自定义迭代器修复此问题有一个新想法。

I'm trying to combine three signal waveforms into a single, interleaved waveform. I need to know the best way to do it in C++ STL. Better solutions would use as much C++ STL style as possible, avoid redundant code, etc. Is there some STL "tuple" type class that would do this for me? I need contiguous storage at all times for backward compatibility with other code (therefore, vector). The best solution would be correct and easy to understand. Space and speed are not as high of a priority as correctness and ease of understanding.

The output waveform must be ordered like this: first sample from first channel, first sample from second channel, first sample from third channel, then continue with the second sample from each channel and repeat for all samples. I know that all three input waveforms have the same number of samples.

In Matlab, I would have done it like this:

function outputWaveform=Interleave3(a, b, c)
outputWaveform=zeros([1 3*length(a)]);
outputWaveform(1:3:end)=a(:);
outputWaveform(2:3:end)=b(:);
outputWaveform(3:3:end)=c(:);

This is my first C++ STL attempt:

typedef vector<double>  dVector;
typedef vector<double>::iterator  dVectorIT;
dVector Interleave3(dVector a, dVector b, dVector c)
{
    dVector result(0, 3*a.size());
    dVectorIT aIT=a.begin(), bIT=b.begin(), cIT=c.begin(), rIT=result.begin();
    for(; aIT != a.end(); ++aIT, ++bIT, ++cIT)
    {
        *rIT++=*aIT;
        *rIT++=*bIT;
        *rIT++=*cIT;
    }
    return  result;
}

It works, but is there a better way to do this? I hoped there might be some clever way to do it in one line with transform(). Can you append b to a, then c to a, then transform the temporary "a1a2a3...-b1b2b3...-c1c2c3..." vector into "a1b1c1a2b2c2a3b3c3..."?

Bonus question: I also need the inverse operation (to split an output waveform of 3*N samples into 3 vectors of N samples each). The Matlab solution is quite easy:

function [a, b, c]=Deinterleave3(outputWaveform)
a=outputWaveform(1:3:end);
b=outputWaveform(2:3:end);
c=outputWaveform(3:3:end);

C++ STL seems fairly awkward, and I bet there's a better way to do it than this:

typedef vector<double>  dVector;
typedef vector<double>::iterator  dVectorIT;
void Deinterleave3(dVector outputWaveform, dVector &a, dVector &b, dVector &c)
{
    ASSERT( !(outputWaveform.size()%3) );
    a.clear(); b.clear(); c.clear();
    dVectorIT oIT=outputWaveform.begin();
    for(; oIT != outputWaveform.end(); )
    {
        a.push_back( *oIT++ );
        b.push_back( *oIT++ );
        c.push_back( *oIT++ );
    }
}

Is there some clever combination of transform() and back_inserter() which would do the inverse operation? Again, using a temporary vector would be acceptable.

Boost has a "zip iterator," but I can't figure out if it would perform either the interleaving or deinterleaving operation.

EDIT: fixed the missing angle brackets (<>). The HTML filter ate them! Also, I have a new idea about how to fix this with a custom iterator.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

桃扇骨 2024-09-24 05:57:50

如果您愿意使用Boost,可以使用 切片 使语法非常接近您在 Matlab 中的代码。这是 Interleave3 函数的 C++ 版本:

template<typename V>
V Interleave3(V const& a, V const& b, V const& c)
{
    using namespace boost::numeric::ublas;

    V v(a.size() + b.size() + c.size());
    vector_slice<V>(v, slice(0, 3, a.size())) = a;
    vector_slice<V>(v, slice(1, 3, b.size())) = b;
    vector_slice<V>(v, slice(2, 3, c.size())) = c;

    return v;
}

问题是您必须使用 boost::numeric::ublas::vector,而不是使用 std::vector。

If you're willing to use Boost, you can use slices to get syntax very close to your code in Matlab. Here's a C++ version of your Interleave3 function:

template<typename V>
V Interleave3(V const& a, V const& b, V const& c)
{
    using namespace boost::numeric::ublas;

    V v(a.size() + b.size() + c.size());
    vector_slice<V>(v, slice(0, 3, a.size())) = a;
    vector_slice<V>(v, slice(1, 3, b.size())) = b;
    vector_slice<V>(v, slice(2, 3, c.size())) = c;

    return v;
}

The catch is that instead of using std::vector you have to use boost::numeric::ublas::vector.

一瞬间的火花 2024-09-24 05:57:50

我不确定交错,但您可以使用 for_each 来解交错。您仍然需要添加额外的错误检查(源大小是否正确等):

#include <iostream>
#include <vector>

typedef std::vector<double> dVector;
typedef dVector::iterator dVectorIT;

class DeInterleave
{
public:
    DeInterleave(std::vector<dVector>& output) : output_(output), currentIndex_(0) { }
    void operator()(const dVector::value_type& item)
    {
        output_[currentIndex_].push_back(item);
        currentIndex_ = (currentIndex_ + 1) % output_.size();
    }

private:
    std::vector<dVector>& output_;
    int currentIndex_;
};

int main()
{
    dVector source;
    source.push_back(5.0);
    source.push_back(6.0);
    source.push_back(8.0);
    source.push_back(2.0);
    source.push_back(2.0);
    source.push_back(1.0);
    std::vector<dVector> dest(3);

    std::for_each(source.begin(), source.end(), DeInterleave(dest));

    std::cout << dest[0].size() << " " << dest[0][0] << ":" << dest[0][1] << std::endl;
    std::cout << dest[1].size() << " " << dest[1][0] << ":" << dest[1][1] << std::endl;
    std::cout << dest[2].size() << " " << dest[2][0] << ":" << dest[2][1] << std::endl;

    return 0;
}

I'm not sure about interleaving but you can use for_each to deinterleave. You would still want to add additional error checking (that the source size is correct etc):

#include <iostream>
#include <vector>

typedef std::vector<double> dVector;
typedef dVector::iterator dVectorIT;

class DeInterleave
{
public:
    DeInterleave(std::vector<dVector>& output) : output_(output), currentIndex_(0) { }
    void operator()(const dVector::value_type& item)
    {
        output_[currentIndex_].push_back(item);
        currentIndex_ = (currentIndex_ + 1) % output_.size();
    }

private:
    std::vector<dVector>& output_;
    int currentIndex_;
};

int main()
{
    dVector source;
    source.push_back(5.0);
    source.push_back(6.0);
    source.push_back(8.0);
    source.push_back(2.0);
    source.push_back(2.0);
    source.push_back(1.0);
    std::vector<dVector> dest(3);

    std::for_each(source.begin(), source.end(), DeInterleave(dest));

    std::cout << dest[0].size() << " " << dest[0][0] << ":" << dest[0][1] << std::endl;
    std::cout << dest[1].size() << " " << dest[1][0] << ":" << dest[1][1] << std::endl;
    std::cout << dest[2].size() << " " << dest[2][0] << ":" << dest[2][1] << std::endl;

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文