大多数答案都建议对初始容器进行洗牌。如果不想修改的话,还是可以使用这种方式的,但是首先需要复制容器。 The solution of @pmr(这很好,因为他把它变成了一个函数)然后会变成:
template <typename InputIterator, typename Size, typename OutputIterator>
void take_random_n(InputIterator first, InputIterator last,
Size n, OutputIterator result)
{
typedef typename std::iterator_traits<InputIterator>::value_type value_type;
std::vector<value_type> shufflingVec(first, last);
std::random_shuffle(shufflingVec.begin(), shufflingVec.end());
std::copy(shufflingVec.begin(), shufflingVec.begin() + n, result);
}
但是,如果包含的元素很重并且需要一些时间来复制,则复制整个容器可能会非常昂贵。在这种情况下,最好改组索引列表:
template <typename InputIterator, typename Size, typename OutputIterator>
void take_random_n(InputIterator first, InputIterator last,
Size n, OutputIterator result)
{
typedef typename
std::iterator_traits<InputIterator>::value_type value_type;
typedef typename
std::iterator_traits<InputIterator>::difference_type difference_type;
difference_type size = std::distance(first, last);
std::vector<value_type> indexesVec(
boost::counting_iterator<size_t>(0),
boost::counting_iterator<size_t>(size));
// counting_iterator generates incrementing numbers. Easy to implement if you
// can't use Boost
std::random_shuffle(indexesVec.begin(), indexesVec.end());
for (Size i = 0 ; i < n ; ++i)
{
*result++ = *std::advance(first, indexesVec[i]);
}
}
// Disclaimer: I have not tested the code above!
您会注意到,根据您使用的迭代器的类型,后一种解决方案的执行方式会非常不同:使用随机访问迭代器(如指针或vector<T>::iterator),它会没问题,但对于其他类型的迭代器,使用std::distance 和对std::advance 的大量调用会产生相当大的开销。