这是从容器中获取随机元素的OK范围方法吗?

时间:2011-12-02 14:09:53

标签: c++ templates random c++11

最近我决定试用新的c ++ 11随机库,有一件事让我想到......从容器中挑选随机元素时摆脱[rand()%nelemennts]。原因是我想要可重复生成,当使用rand封装是不存在的,因为

auto set_a=generateSet(nelements1); //generateSet calls rand
auto set_b=generateSet(nelements2); //so set_b is determined by the previous line :(

所以这就是我提出的: (注意,这不是线程安全的,它设计为安全的方式,调用generateSet不会影响彼此(通过改变rand内部值的状态))

template<typename container_type,typename element_type >
class RandElemGetter
{

    const container_type& containter_ref;
    std::uniform_int_distribution<size_t> distribution;
    std::mt19937 engine;
public:
    RandElemGetter(container_type& container): containter_ref(container),distribution(0,container.size()-1)
    {

    }
    element_type get()
    {
        return containter_ref[distribution(engine)];
    }
};

用法:

{
vector<int> v{1,2,3,1701,1729};
vector<int> result;
RandElemGetter<vector<int>,int> reg_v(v);
for(size_t i=0;i<nelements;++i)
result.push_back(reg_v.get());
}

这是可行的解决方案吗?我知道它不是线程安全的,这不是重点。我想知道是否有更好的“范围”方式从随机访问容器中获取随机元素。可以使用std :: advance对所有人进行修改。

2 个答案:

答案 0 :(得分:2)

RandElemGetter(container_type container):
   containter_ref(container),distribution(0,container.size()-1)

这将按值获取容器,创建临时副本,并存储对该副本的引用。一旦构造函数完成,引用就无效了。

您需要存储副本,或通过引用传递参数。最后通过常量引用传递复杂对象是个好主意,以避免不必要的复制。

答案 1 :(得分:1)

  • 我会使用<typename container_type, typename value_type = container_type::typename value_type>。 STL容器的value_types有typedef,所以通常不需要重复自己。
  • 正确的解决方案确实是返回*std::advance(containter_ref.begin(), distribution(engine));
  • 我将get()重命名为operator(),并提供result_type typedef以符合STL模型AdaptableGenerator

您可能希望从原始STL获得SGI random_sample的峰值;我相信GNU仍然将其作为扩展。