Last active
August 29, 2015 14:23
-
-
Save ak110/29f9d344adc6528f66ed to your computer and use it in GitHub Desktop.
ランダムに指定個数を非復元抽出するRange Adapterを作ってみた。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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