Home > database >  Is there an efficient way to use random number deduplication?
Is there an efficient way to use random number deduplication?

Time:04-19

I making a program that uses random numbers. I wrote the code as below, but the number of loops was higher than I expected Is there an efficient way to use random number deduplication?

#include <iostream>
#include <cstdlib>
#include <ctime>
#define MAX 1000
int main(void)
{
    int c[MAX] = {};
    int i, j = 0;
    srand((unsigned int)time(NULL));
    for (i = 0; i < MAX; i  )
    {
        c[i] = rand() % 10000;
        for (j = 0; j < i; j  )
        {
            if (c[i] == c[j])
            {
                i--;
                break;
            }
        }
    }
    for (i = 0; i < MAX; i  )
    {
        std::cout << c[i] << std::endl;
    }
    return 0;
}

CodePudding user response:

You can make use of std::shuffle.

Populate the vector with increasing numbers till MAX and then shuffle it.

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <vector>
 
#define MAX 1000

int main()
{  
    std::vector<int> v(MAX) ; // vector with 1000 ints.
    std::iota (std::begin(v), std::end(v), 0);
 
    std::random_device rd;
    std::mt19937 g(rd());
 
    std::shuffle(v.begin(), v.end(), g);
 
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    
    std::cout << "\n";
}

DEMO

CodePudding user response:

Here is a version that avoids initializing an array with the size of max like the answer of TruthSeeker, so it takes less memory. It has uniform sampling.

#include <random>
#include <cassert>
#include <iostream>
#include <unordered_map>
#include <vector>

std::vector<int> random_set(int count, int maximum_value)
{
    assert(count <= maximum_value   1);

    std::vector<int> output;
    std::unordered_map<int, int> jump;

    auto helper_maximum = maximum_value;

    std::random_device rd;
    std::mt19937 gen(rd());

    for (int i = 0; i < count;   i, --helper_maximum)
    {
        const auto selector_origin = std::uniform_int_distribution<int>(0, helper_maximum)(gen);
        auto selector = selector_origin;

        while (true)
        {
            auto it = jump.find(selector); 
            if (it == jump.end()) break;
            selector = it->second;
        }

        jump[selector_origin] = helper_maximum;
        output.push_back(selector);
    }

    return output;
}

int main()
{
    random_set(10, 15000);
}

CodePudding user response:

What you are describing is sampling without replacement. std::sample does exactly that, you just need to supply it with your population of numbers.

std::ranges::views::iota can be your population without having to store 10000 numbers.

#include <algorithm>
#include <random>
#include <ranges>
#include <iostream>

int main()
{
    std::vector<int> c(1000);
    std::mt19937 gen(std::random_device{}()); // or a better initialisation
    auto numbers = std::ranges::views::iota(0, 9999);
    std::sample(numbers.begin(), numbers.end(), c.begin(), 1000, gen);

    for (int i : c) 
    {
        std::cout << i << std::endl;
    }
}

See it live

  • Related