mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-22 14:55:36 +08:00
refs #481 Algorithms to copy random elements from containers.
This commit is contained in:
@@ -9,8 +9,11 @@
|
||||
|
||||
#include "samplesalgorithm.h"
|
||||
#include "blackmisc/algorithm.h"
|
||||
#include "blackmisc/sequence.h"
|
||||
#include "blackmisc/collection.h"
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <numeric>
|
||||
|
||||
namespace BlackMiscTest
|
||||
{
|
||||
@@ -20,6 +23,41 @@ namespace BlackMiscTest
|
||||
*/
|
||||
int CSamplesAlgorithm::samples()
|
||||
{
|
||||
BlackMisc::CSequence<int> seq;
|
||||
for (int i = 1; i <= 100; ++i)
|
||||
{
|
||||
seq.push_back(i);
|
||||
}
|
||||
const int samples = 200;
|
||||
BlackMisc::CSequence<int> means;
|
||||
{
|
||||
for (int i = 0; i < samples; ++i)
|
||||
{
|
||||
auto randoms = seq.randomElements(10);
|
||||
means.push_back(std::accumulate(randoms.cbegin(), randoms.cend(), 0) / 10);
|
||||
}
|
||||
int mean = std::accumulate(means.cbegin(), means.cend(), 0) / samples;
|
||||
int stdDev = std::sqrt(std::accumulate(means.cbegin(), means.cend(), 0, [ & ](int a, int n) { return a + (n - mean) * (n - mean); }) / samples);
|
||||
qDebug() << "randomElements";
|
||||
qDebug() << "means:" << means;
|
||||
qDebug() << "mean of the means:" << mean;
|
||||
qDebug() << "std deviation of the means:" << stdDev;
|
||||
}
|
||||
means.clear();
|
||||
{
|
||||
for (int i = 0; i < samples; ++i)
|
||||
{
|
||||
auto randoms = seq.sampleElements(10);
|
||||
means.push_back(std::accumulate(randoms.cbegin(), randoms.cend(), 0) / 10);
|
||||
}
|
||||
int mean = std::accumulate(means.cbegin(), means.cend(), 0) / samples;
|
||||
int stdDev = std::sqrt(std::accumulate(means.cbegin(), means.cend(), 0, [ & ](int a, int n) { return a + (n - mean) * (n - mean); }) / samples);
|
||||
qDebug() << "sampleElements";
|
||||
qDebug() << "means:" << means;
|
||||
qDebug() << "mean of the means:" << mean;
|
||||
qDebug() << "std deviation of the means:" << stdDev;
|
||||
}
|
||||
|
||||
QStringList src { "a1", "a2", "a3", "b1", "b2", "b3", "c1", "c2", "c3" };
|
||||
std::random_shuffle(src.begin(), src.end());
|
||||
qDebug() << src;
|
||||
|
||||
@@ -12,12 +12,75 @@
|
||||
#ifndef BLACKMISC_ALGORITHM_H
|
||||
#define BLACKMISC_ALGORITHM_H
|
||||
|
||||
#include <QThreadStorage>
|
||||
#include <QtGlobal>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Private
|
||||
{
|
||||
//! \private A high quality deterministic pseudo-random number generator.
|
||||
//! \threadsafe
|
||||
inline std::mt19937 &defaultRandomGenerator()
|
||||
{
|
||||
static QThreadStorage<std::mt19937> rng;
|
||||
if (rng.hasLocalData()) { rng.setLocalData(std::mt19937(qrand())); }
|
||||
return rng.localData();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Use the random number generator rng to choose n elements from the range [in,end) and copy them to out.
|
||||
*/
|
||||
template <typename ForwardIt, typename OutputIt, typename Generator>
|
||||
void copyRandomElements(ForwardIt in, ForwardIt end, OutputIt out, int n, Generator &&rng)
|
||||
{
|
||||
for (auto size = std::distance(in, end); in != end && n > 0; ++in, --size)
|
||||
{
|
||||
if (std::uniform_int_distribution<>(0, size - 1)(rng) < n)
|
||||
{
|
||||
*out++ = *in;
|
||||
--n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Randomly choose n elements from the range [in,end) and copy them to out.
|
||||
*/
|
||||
template <typename ForwardIt, typename OutputIt>
|
||||
void copyRandomElements(ForwardIt in, ForwardIt end, OutputIt out, int n)
|
||||
{
|
||||
copyRandomElements(in, end, out, n, Private::defaultRandomGenerator());
|
||||
}
|
||||
|
||||
/*!
|
||||
* Split the range [in,end) into n equal chunks and use the random number generator rng to choose one element from each.
|
||||
*/
|
||||
template <typename ForwardIt, typename OutputIt, typename Generator>
|
||||
void copySampleElements(ForwardIt in, ForwardIt end, OutputIt out, const int n, Generator &&rng)
|
||||
{
|
||||
for (const auto size = std::distance(in, end); in != end && n > 0; )
|
||||
{
|
||||
const auto index = std::uniform_int_distribution<>(0, size / n - 1)(rng);
|
||||
std::advance(in, index);
|
||||
*out++ = *in;
|
||||
std::advance(in, size / n - index);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Split the range [in,end) into n equal chunks and randomly choose one element from each.
|
||||
*/
|
||||
template <typename ForwardIt, typename OutputIt>
|
||||
void copySampleElements(ForwardIt in, ForwardIt end, OutputIt out, int n)
|
||||
{
|
||||
copySampleElements(in, end, out, n, Private::defaultRandomGenerator());
|
||||
}
|
||||
|
||||
/*!
|
||||
* Topological sorting algorithm.
|
||||
*
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "blackmiscexport.h"
|
||||
#include "iterator.h"
|
||||
#include "predicates.h"
|
||||
#include "algorithm.h"
|
||||
#include <QtGlobal>
|
||||
#include <QDebug>
|
||||
#include <algorithm>
|
||||
@@ -128,6 +129,22 @@ namespace BlackMisc
|
||||
return containsBy(BlackMisc::Predicates::MemberEqual(k0, v0, keysValues...));
|
||||
}
|
||||
|
||||
//! Copy n elements from the container at random.
|
||||
Derived randomElements(int n) const
|
||||
{
|
||||
Derived result;
|
||||
BlackMisc::copyRandomElements(derived().begin(), derived().end(), std::inserter(result, result.end()), n);
|
||||
return result;
|
||||
}
|
||||
|
||||
//! Copy n elements from the container, randomly selected but evenly distributed.
|
||||
Derived sampleElements(int n) const
|
||||
{
|
||||
Derived result;
|
||||
BlackMisc::copySampleElements(derived().begin(), derived().end(), std::inserter(result, result.end()), n);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
Derived &derived() { return static_cast<Derived &>(*this); }
|
||||
const Derived &derived() const { return static_cast<const Derived &>(*this); }
|
||||
|
||||
Reference in New Issue
Block a user