Four digit random number without digit repetition

后端 未结 5 1614
日久生厌
日久生厌 2021-01-16 18:46

Is there any way you can have a 4 digit number without repetition - e.g. not 1130 but 1234? I read std::random_shuffle could do this b

相关标签:
5条回答
  • 2021-01-16 19:11

    If you can count how many valid (i.e. acceptable) sequences exist, and you can devise a bijective function that maps from this counter to each valid sequence instance then things become trivial.

    If I understand your example correctly, you want to generate a random 4 digit sequence ABCD (representing an integer in the range [0,9999]) where digits A, B, C and D are different from one another.

    There are 5040 such valid sequences: 10 * 9 * 8 * 7.

    Given any integer in the range [0, 5039], the following function will return a valid sequence (i.e. one in which each digit is unique), represented as an integer:

    int counter2sequence(int u) {
      int m = u/504;
      u %= 504;
      int h = u/56;
      u %= 56;
      int t = u/7;
      u %= 7;
    
      const int ih = h;
      const int it = t;
    
      if (ih >= m) ++h;
      if (it >= ih) ++t;
      if (t >= m) ++t;
      if (u >= it) ++u;
      if (u >= ih) ++u;
      if (u >= m) ++u;
    
      return ((m*10 + h)*10 + t)*10 + u;
    }
    

    E.g.

    counter2sequence(0) => 0123
    counter2sequence(5039) => 9876
    
    0 讨论(0)
  • 2021-01-16 19:11

    Another method, using only standard data and numeric algorithms.

    #include <random>
    #include <array>
    #include <iostream>
    #include <numeric>
    
    template<class Engine>
    int unrepeated_digits(int ndigits, Engine &eng) {
        std::array<int, 10> digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        auto add_digit = [](auto x, auto digit) {
            return x * 10 + digit;
        };
        std::shuffle(std::begin(digits), std::end(digits), eng);
        return std::accumulate(std::begin(digits), std::next(std::begin(digits), ndigits), 0, add_digit);
    }
    
    int main() {
        std::random_device rnd;
        std::default_random_engine eng(rnd());
    
        for (int i = 0; i < 10; ++i)
            std::cout << unrepeated_digits(4, eng) << std::endl;
    }
    

    example output:

    7623
    3860
    9563
    9150
    3219
    8652
    4789
    2457
    1826
    9745
    
    0 讨论(0)
  • 2021-01-16 19:19

    I don't see a problem with std::random_shuffle:

    #include <iostream>
    #include <string>
    #include <algorithm>
    #include <random>
    #include <chrono>
    
    int main()
    {
        std::string s;    
        std::generate_n(std::back_inserter(s), 10,
            []() { static char c = '0'; return c++; });
        // s is now "0123456789"
    
        std::mt19937 gen(std::random_device{}());
    
        // if 0 can't be the first digit
        std::uniform_int_distribution<size_t> dist(1, 9);
        std::swap(s[0], s[dist(gen)]);
    
        // shuffle the remaining range
        std::shuffle(s.begin() + 1, s.end(), gen); // non-deprecated version
    
        // convert only first four
        auto x = std::stoul(s.substr(0, 4));
        std::cout << x << std::endl;
    }
    

    Live on Coliru

    0 讨论(0)
  • 2021-01-16 19:22

    One possibility is to generate a string containing the digits, and to use the C++14 function std::experimental::sample()

    #include <iostream>
    #include <random>
    #include <string>
    #include <iterator>
    #include <experimental/algorithm>
    
    int main() {
    std::string in = "0123456789", out;
    do {
        out="";
        std::experimental::sample(in.begin(), in.end(), std::back_inserter(out), 4, std::mt19937{std::random_device{}()});
        std::shuffle(out.begin(), out.end(), std::mt19937{std::random_device{}()});
      } while (out[0]=='0');
      std::cout << "random four-digit number with unique digits:"  << out << '\n';
    }
    

    Edit:

    Changed to prevent a result that starts with a 0. Hat tip to @Bathsheba who indicated that this could be a problem.

    0 讨论(0)
  • 2021-01-16 19:25

    I think you need to generate each digit separately. For example you have array from 0 to 9 with 0..9 digits. For first digit you generate number from 0 to 9 and pick up digit from this array. Then you swap this array element t with last element of array. For second digit you generate number form 0 to 8. And so on.

    0 讨论(0)
提交回复
热议问题