计算两个前向指标之间的截断平均值

Computing truncated mean between two forward indicators

我已经通过函数 truncated_mean(std::vector& v, double trimming fraction) 计算了向量的截断平均值。此函数将向量 v 和我们想要移除以计算平均值的分数作为输入(例如 10%,因此我们移除最高和最低 10% 的值,然后计算平均值),我使用标准库创建了它。

例如v = [0,1,2....,9],则truncated_mean(v, 0.10) = 4.5.

现在,我想重用相同的函数,但我不想使用 v 作为输入,而是想使用 2 个前向迭代器,v.begin() 和 v.end()。我获得了类型名称 forward 的模板,我应该使用它来检查其 value_type(通过 std::iterator_traits 访问)是否满足特定条件。我对这个问题的理解是,首先我需要检查输入是否属于一个向量,然后我应该从那里访问向量本身来计算截断的均值。

如何调整我的函数以将向量的开头和结尾而不是向量本身作为输入?

假设传入的序列已排序,您可以简单地使用 std::distance 计算长度并在开始和结束时跳过适当数量的元素:

编辑:std::accumulate 用于随机访问迭代器的扩展代码;如果允许使用 C++20 功能,请使用概念而不是区分迭代器类型和附加参数。

template<typename RandomAccessIterator>
double truncated_mean_impl(RandomAccessIterator begin, RandomAccessIterator end, double trimming_fraction, std::random_access_iterator_tag)
{
    if (trimming_fraction < 0)
    {
        throw std::range_error("trimming_fraction must not be negative");
    }
    if(trimming_fraction >= 0.5)
    {
        return std::numeric_limits<double>::quiet_NaN(); // no elements left after trimming
    }

    auto const count = std::distance(begin, end);
    auto const skippedElementCountFront = static_cast<decltype(count)>(count * trimming_fraction);
    auto const summandCount = count - 2 * skippedElementCountFront;

    return std::accumulate<RandomAccessIterator, double>(begin + skippedElementCountFront, end - skippedElementCountFront, 0) / summandCount;
}


template<typename ForwardIterator>
double truncated_mean_impl(ForwardIterator begin, ForwardIterator end, double trimming_fraction, std::forward_iterator_tag)
{
    if (trimming_fraction < 0)
    {
        throw std::range_error("trimming_fraction must not be negative");
    }
    if(trimming_fraction >= 0.5)
    {
        return std::numeric_limits<double>::quiet_NaN(); // no elements left after trimming
    }

    auto const count = std::distance(begin, end);

    auto const skippedElementCountFront = static_cast<decltype(count)>(count * trimming_fraction);
    
    // skip elements in the front
    for (auto i = skippedElementCountFront; i != 0; --i, ++begin) {}

    auto const summandCount = count - 2 * skippedElementCountFront;

    double sum = 0;

    for (auto i = summandCount; i != 0; --i, ++begin)
    {
        sum += *begin;
    }

    return sum / summandCount;
}

template<typename ForwardIterator>
double truncated_mean(ForwardIterator begin, ForwardIterator end, double trimming_fraction)
{
    return truncated_mean_impl<ForwardIterator>(begin, end, trimming_fraction, typename std::iterator_traits<ForwardIterator>::iterator_category());
}

int main()
{
    std::vector<int> const values  { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    std::cout << truncated_mean(values.cbegin(), values.cend(), 0.1) << '\n';
}

如果输入序列未排序并且您不能或不想对输入进行排序,则将元素复制到新向量并将您的原始算法应用于该向量可能是最好的。