【问题标题】:Fancy indexing in C++ using boost::range使用 boost::range 在 C++ 中进行花式索引
【发布时间】:2011-11-04 01:05:20
【问题描述】:

我想使用 boost::range 来完成类似于 NumPy 和 Matlab 中可用的“花式索引”的东西。具体来说,我想使用另一个容器的元素作为索引来选择一个可索引容器的某些元素。例如,可以在 Python 中执行以下操作:

>>> squares = numpy.arange(10)**2  # Step 1 - setup squares
>>> indices = numpy.array([1,3,4]) # Step 2 - setup indices
>>> squares[indices]               # Step 3 - fancy indexing
array([ 1, 9, 16])

在 C++ 中,使用 boost::range,我认为上面的代码看起来像这样:

#include "sampled.hpp"
#include <boost/assign/std/vector.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/counting_range.hpp>
#include <iostream>
#include <vector>

using namespace boost;
using namespace boost::adaptors;
using namespace boost::assign;
using namespace boost::lambda;
using namespace std;

int main(int argc, char** argv)
{
    // Step 1 - setup squares
    vector<int> squares;
    push_back(
        squares,
        counting_range(1,11) | transformed(ret<int>(_1 * _1))
    );

    // Step 2 - setup indices
    vector<size_t> indices;
    indices += 1,3,4;

    // Step 3 - fancy indexing
    for_each(
        squares | sampled(indices),
        cout << _1 << constant(" ")
    );

    return 0;
}

由于现有范围适配器(boost::adaptor::indexed)已使用名称“indexed”,因此我在上述代码中将尚未实现的索引适配器称为“sampled”。

有谁知道这样的适配器是否已经存在于某个地方的 boost 中,或者是否有他们愿意分享的实现?我已经开始尝试自己实现它,首先编写一个“sampled_iterator”(使用 iterator_adaptor),然后编写一个“sampled_range”(使用 iterator_range),但我发现它非常棘手。

【问题讨论】:

  • +1,有趣的问题和问题陈述。我从未使用过 Boost 的这一部分,但这可能会在未来发生变化。这个特性的一个合理有效的实现肯定会让更广泛的人感兴趣,所以如果你让它工作,一定要发布它。 ;-)

标签: c++ templates boost numpy boost-range


【解决方案1】:

好的,所以我设法使用 boost::permutation_iterator 作为范围适配器的基础。由于使用了 permutation_iterator,我将范围适配器称为“permuted”而不是“sampled”,因为它在问题的代码摘录中被引用。所以 C++ 版本的 numpy 代码是这样的:

// Step 3
for_each(
    squares | permuted(indices),
    cout << _1 << constant(" ")
);

这是“置换”的代码:

#pragma once

#include <boost/range/adaptor/argument_fwd.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/iterator/permutation_iterator.hpp>

template <class IndexContainer, class ElementRange>
class permuted_range :
    public boost::iterator_range<
        boost::permutation_iterator<
            typename boost::range_iterator<ElementRange>::type,
            typename IndexContainer::iterator> >
{
private:
    typedef boost::iterator_range<
        boost::permutation_iterator<
        typename boost::range_iterator<ElementRange>::type,
        typename IndexContainer::iterator> > base;

public:
    permuted_range(IndexContainer& i, ElementRange& r) :
        base(
            boost::make_permutation_iterator(boost::begin(r), i.begin()),
            boost::make_permutation_iterator(boost::begin(r), i.end()))
    { }
};

template <class IndexContainer>
struct permuted_holder : boost::range_detail::holder<IndexContainer>
{
    permuted_holder(IndexContainer i) :
        boost::range_detail::holder<IndexContainer>(i)
    { }
};

template <class ElementRange, class IndexContainer>
inline permuted_range<IndexContainer, ElementRange> operator| (
    ElementRange& r,
    permuted_holder<IndexContainer> i)
{
    return permuted_range<IndexContainer, ElementRange>(i.val, r);
}

template <class ElementRange, class IndexContainer>
inline permuted_range<IndexContainer, const ElementRange> operator| (
    const ElementRange& r,
    permuted_holder<IndexContainer> i)
{
    return permuted_range<IndexContainer, const ElementRange>(i.val, r);
}

static boost::range_detail::forwarder<permuted_holder> permuted =
    boost::range_detail::forwarder<permuted_holder>();

我想可以进行一些改进。 permutation_iterator 似乎是一个相当有效的基础,但也许有更好的选择。有什么想法吗?

【讨论】:

    猜你喜欢
    • 2013-01-07
    • 2019-11-20
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    相关资源
    最近更新 更多