【问题标题】:Averaging and decreasing the array (vector) C++平均和减少数组(向量)C++
【发布时间】:2017-12-08 23:18:24
【问题描述】:

我有一个数组(实际上是std::vector),大小约为 7k 个元素。 如果你画出这个数据,就会有一个燃料燃烧的图表。但我想将此向量从 7k 元素最小化到 721(每 0.5 度)元素或〜 1200(每 0.3 度)。当然我想保存图表一样。我该怎么做? 现在我将大向量中的每 9 个元素转换为新的元素,并从向量的前后均匀地切割其他元素以获得 721 大小。

QVector <double> newVMTVector;
for(QVector <double>::iterator itv = oldVmtDataVector.begin(); itv < oldVmtDataVector.end() - 9; itv+=9){
    newVMTVector.push_back(*itv);
}
auto useless = newVMTVector.size() - 721;
if(useless%2 == 0){
    newVMTVector.erase(newVMTVector.begin(), newVMTVector.begin() + useless/2);
    newVMTVector.erase(newVMTVector.end() - useless/2, newVMTVector.end());
}
else{
    newVMTVector.erase(newVMTVector.begin(), newVMTVector.begin() + useless/2+1);
    newVMTVector.erase(newVMTVector.end() - useless/2, newVMTVector.end());
}
newVMTVector.squeeze();
oldVmtDataVector.clear();
oldVmtDataVector = newVMTVector;

我可以发誓有一种算法可以平均和减少数组。

【问题讨论】:

  • 您当前的代码没有做什么?
  • 您可以尝试使用 std::transform 应用自定义 lambda 来平均数字。
  • 我不确定我是否理解这个问题。您是说您有某种类型的向量,其中包含表示图表的信息?您是否想以某种方式减少向量的元素数量,以便仍然能够以较低的分辨率绘制相同的图表?
  • 在什么方面更好?表现?图表的准确性?
  • "~7k" -- 到底有多少? 7200? 7201? |我看到这被标记为“stl”和“boost”,但是有一个来自 Qt 的向量类......为什么?|为什么你需要从你刚刚填充的向量中删除东西?|插值可能会有所帮助。

标签: c++ arrays vector boost stl


【解决方案1】:

您需要的是插值。有许多库提供许多类型的插值。这个非常轻量级,易于设置和运行:

http://kluge.in-chemnitz.de/opensource/spline/

您需要做的就是创建包含 X 值的第二个向量,传递两个向量以生成样条曲线,并每隔 0.5 度或其他任何值生成插值结果:

std::vector<double> Y; // Y is your current vector of fuel combustion values with ~7k elements
std::vector<double> X;
X.reserve(Y.size());

double step_x = 360 / (double)Y.size();
for (int i = 0; i < X.size(); ++i)
    X[i] = i*step_x;

tk::spline s;
s.set_points(X, Y);
double interpolation_step = 0.5;

std::vector<double> interpolated_results;
interpolated_results.reserve(std::ceil(360/interpolation_step) + 1);
for (double i = 0.0, int j = 0; i <= 360; i += interpolation_step, ++j) // <= in order to obtain range <0;360>
    interpolated_results[j] = s(i);

if (fmod(360, interpolation_step) != 0.0) // for steps that don't divide 360 evenly, e.g. 0.7 deg, we need to close the range
    interpolated_results.back() = s(360);

// now interpolated_results contain values every 0.5 degrees

这应该让您了解如何使用此类库。如果您需要其他插值类型,只需找到适合您需要的插值类型即可。用法应该差不多。

【讨论】:

    【解决方案2】:

    按照我的理解,您想选择元素 [0, k, 2k, 3k ... ],其中 n 为 10 或 n 为 6。

    这是一个简单的例子:

    template <typename It>
    It strided_inplace_reduce(It it, It const last, size_t stride) {
        It out = it;
        if (stride < 1) return last;
    
        while (it < last)
        {
            *out++ = *it;
            std::advance(it, stride);
        }
    
        return out;
    }
    

    对非随机访问迭代器进行一些概括:

    Live On Coliru

    #include <iterator>
    
    namespace detail {
        // version for random access iterators
        template <typename It>
        It strided_inplace_reduce(It it, It const last, size_t stride, std::random_access_iterator_tag) {
            It out = it;
            if (stride < 1) return last;
    
            while (it < last)
            {
                *out++ = *it;
                std::advance(it, stride);
            }
    
            return out;
        }
    
        // other iterator categories
        template <typename It>
        It strided_inplace_reduce(It it, It const last, size_t stride, ...) {
            It out = it;
            if (stride < 1) return last;
    
            while (it != last) {
                *out++ = *it;
                for (size_t n = stride; n && it != last; --n)
                {
                    it = std::next(it);
                }
            }
    
            return out;
        }
    }
    
    template <typename Range>
    auto strided_inplace_reduce(Range& range, size_t stride) {
        using std::begin;
        using std::end;
    
        using It = decltype(begin(range));
        It it = begin(range), last = end(range);
    
        return detail::strided_inplace_reduce(it, last, stride, typename std::iterator_traits<It>::iterator_category{});
    }
    
    #include <vector>
    #include <list>
    #include <iostream>
    
    int main() {
        {
            std::vector<int> v { 1,2,3,4,5,6,7,8,9 };
            v.erase(strided_inplace_reduce(v, 2), v.end());
    
            std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout << "\nv: ", " "));
        }
        {
            std::list<int> l { 1,2,3,4,5,6,7,8,9 };
            l.erase(strided_inplace_reduce(l, 4), l.end());
    
            std::copy(l.begin(), l.end(), std::ostream_iterator<int>(std::cout << "\nl: ", " "));
        }
    }
    

    打印

    v: 1 3 5 7 9 
    l: 1 5 9 
    

    【讨论】:

    • 老实说,在我看来,这更像是一个信号处理问题——将信号从一个统一速率重新采样到另一个(速率相当随意,因为输入样本的数量似乎未知)。我正在寻找类似 scipy 或 Matlab resample 的 C++ 等价物。
    • 顺便说一句,在std::list 的示例中——当步幅为 4 时,它不应该是位置 0、4 和 8 的元素吗?即1 5 9 而不是1 6?实时示例打印了正确的结果,所以我猜您只是忘记更新答案中的结果。
    • @DanMašek 可能,但这不是他所描述的。是的,输出是复制粘贴问题(如果您点击实时链接,您可以看到)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多