Skip to content

Instantly share code, notes, and snippets.

@ak110
Last active August 29, 2015 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ak110/29f9d344adc6528f66ed to your computer and use it in GitHub Desktop.
Save ak110/29f9d344adc6528f66ed to your computer and use it in GitHub Desktop.
ランダムに指定個数を非復元抽出するRange Adapterを作ってみた。
#include <vector>
#include <boost/range.hpp>
using namespace std;
namespace RangeAdapter {
namespace Detail {
template<class Range>
struct RandomSampledRange;
// Range
template<class Range>
struct RandomSampledRange {
// イテレータ
struct iterator {
typedef forward_iterator_tag iterator_category;
typedef typename boost::range_value<Range>::type value_type;
typedef typename boost::range_difference<Range>::type difference_type;
typedef typename boost::range_pointer<Range>::type pointer;
typedef typename boost::range_reference<Range>::type reference;
const RandomSampledRange<Range>& r;
size_t index;
iterator& operator++() { ++index; return *this; }
iterator operator++(int) { auto t = *this; ++(*this); return t; }
reference operator*() const { return *(std::begin(r.range) + r.indices[index]); }
bool operator==(const iterator& other) const { return index == other.index; }
bool operator!=(const iterator& other) const { return index != other.index; }
};
typedef iterator const_iterator;
Range& range;
vector<size_t> indices;
const size_t count;
template<class URNG>
RandomSampledRange(Range& range, URNG&& g, size_t count)
: range(range), indices(boost::size(range)), count((min)(count, boost::size(range))) {
for (size_t i = 0, n = indices.size(); i < n; i++)
indices[i] = i;
shuffle(indices.begin(), indices.end(), g);
}
iterator begin() const { return { *this, size_t() }; }
iterator end() const { return { *this, count }; }
};
// Rangeへ渡す値を一時的に持つためのもの
template<class URNG>
struct RandomSampleHolder { URNG&& g; size_t count; };
// operator|
template<class Range, class URNG>
inline RandomSampledRange<Range> operator|(Range& range, const Detail::RandomSampleHolder<URNG>& holder) {
return RandomSampledRange<Range>(range, holder.g, holder.count);
}
// operator|
template<class Range, class URNG>
inline RandomSampledRange<const Range> operator|(const Range& range, const Detail::RandomSampleHolder<URNG>& holder) {
return RandomSampledRange<const Range>(range, holder.g, holder.count);
}
}
using Detail::RandomSampledRange;
// アダプタ
template<class URNG>
inline Detail::RandomSampleHolder<URNG> RandomSampled(URNG&& g, size_t count = (numeric_limits<size_t>::max)()) {
return Detail::RandomSampleHolder<URNG> { g, count };
}
}
#include <iostream>
#include <random>
#include <boost/range/irange.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm_ext.hpp>
#include <boost/algorithm/string.hpp>
int main(int argc, char* argv[])
{
mt19937 mt((random_device())()); // とても雑に初期化
vector<int> vec;
boost::range::push_back(vec, boost::irange(0, 20));
cout << boost::algorithm::join(
vec
| RangeAdapter::RandomSampled(mt, 10) // 非constバージョン
| boost::adaptors::transformed([] (int& n) { return to_string(n); }),
", ") << endl;
cout << boost::algorithm::join(
boost::irange(0, 20)
| RangeAdapter::RandomSampled(mt, 10) // constバージョン
| boost::adaptors::transformed([] (const int& n) { return to_string(n); }),
", ") << endl;
cout << boost::algorithm::join(
boost::irange(0, 20)
| RangeAdapter::RandomSampled(mt) // 全量
| boost::adaptors::transformed([] (const int& n) { return to_string(n); }),
", ") << endl;
return 0;
}
/*
<実行結果例>
4, 2, 16, 12, 5, 19, 8, 17, 1, 7
10, 5, 11, 3, 2, 17, 8, 0, 13, 18
0, 12, 14, 17, 5, 2, 13, 4, 8, 1, 7, 3, 18, 10, 16, 6, 15, 9, 11, 19
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment