KansaiRobot
KansaiRobot

Reputation: 9992

Using C++ discrete distribution with weights taken from a data structure

I am trying to use discrete distribution (here too. However as you see in the examples you do this by writing:

std::discrete_distribution<int> distribution {2,2,1,1,2,2,1,1,2,2};

or

 std::discrete_distribution<> d({40, 10, 10, 40});

which is fine if you have 10 or four elements with weights. (also I don't know if the parenthesis are necessary)

But I want to use this for 1000 elements. I have these elements in a vector of structs such as:

struct Particle{
   double weight;
};

std::vector<Particle> particles;

as you can see each element of this vector has a weight. I want to use that weight to initialize the discrete distribution.

I could go writing one by one in a very long sentence, but I don't think that is the way. How can I put the weights of the vector in the declaration of the discrete distribution?

Upvotes: 3

Views: 1208

Answers (2)

c z
c z

Reputation: 9027

A view would allow you to get the data required without copying all the data.

std::ranges::transform_view view = particles | std::views::transform([](const Particle& p) { return p.weight; });

To take Arty's example above, that would become:

#include <random>
#include <vector>
#include <iostream>
#include <ranges>

int main()
{
    struct Particle
    {
        double weight = 0;
    };
    std::vector<Particle> particles({{1}, {2}, {3}, {4}});

    std::ranges::transform_view view = particles | std::views::transform([](const Particle& p) { return p.weight; });

    std::discrete_distribution<size_t> distr(view.begin(), view.end());
    std::random_device rd;
    
    for (size_t i = 0; i < 20; ++i)
    {
        std::cout << distr(rd) << " ";
    }
}

Upvotes: 1

Arty
Arty

Reputation: 16747

You may put your all weights into std::vector<double> weights;, then you can initialize your discrete distribution as std::discrete_distribution<> distr(weights.begin(), weights.end());. Code:

std::vector<double> weights;
for (auto const & p: particles)
    weights.push_back(p.weight);
std::discrete_distribution<> distr(weights.begin(), weights.end());

Full working example code:

Try it online!

#include <random>
#include <vector>
#include <iostream>

int main() {
    struct Particle {
        double weight = 0;
    };
    std::vector<Particle> particles({{1}, {2}, {3}, {4}});
    std::vector<double> weights;
    for (auto const & p: particles)
        weights.push_back(p.weight);
    std::discrete_distribution<size_t> distr(weights.begin(), weights.end());
    std::random_device rd;
    for (size_t i = 0; i < 20; ++i)
        std::cout << distr(rd) << " ";
}

Output:

1 3 3 3 2 0 2 1 3 2 3 2 2 1 1 3 1 0 3 1 

Upvotes: 2

Related Questions