2

I am bringing a formatted text file and putting different lines to my array in random positions. However, when I try to get rand() % 8, I get values that I have already had for previous ones. This causes me to lose some lines and leaving some parts of array blank.

How should I modify it so I get unique values from 0 to 7 in random sequence? I am using only what I have learned in class and new stuff is not recommended by instructor. Please help me change the logic of this code.

void get_input(string (&teams)[8][6]) {
    srand(time(NULL));
    string filename;
    double value;
    char buffer[100];
    int diffnum[8];
    string token;
    cout << "Enter the input file: ";
    cin >> filename;
    ifstream infile;
    infile.open (filename.c_str());
    if (infile.is_open()) {
    int teamcounter = 0;
        while (infile.getline (buffer, 100) && teamcounter < 8) {
            int ran = rand()%8;
            for (int find = 0; find < 8; find++) {
                while (diffnum[find] == ran) {
                    ran = rand()%8;
                }
            }
            diffnum[teamcounter] = ran;
            int counter = 0;
            token = strtok (buffer, ",");
            while (counter < 3) {
                if (counter == 0) {
                    teams[ran][counter] = token;
                    token = strtok (NULL, ", ");
                }
                else if (counter == 1) {
                    teams[ran][counter] = token;
                    token = strtok (NULL, ", ");
                }
                else {
                    teams[ran][counter] = token;
                }
                counter++;
            }
            teamcounter++;
        }
        infile.close();
    }
    else {
        cout << "Unable to open file";
        exit (EXIT_FAILURE);
    }
    for (int q =0;q<8;q++) {
        cout << diffnum[q];
    }
    for (int i; i < 8; i++) {
        for (int j = 3; j < 6; j++){
            teams[i][j] = "0";
        }
    }
}
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
user3317141
  • 21
  • 1
  • 4
  • After pondering `std::random_shuffle` as is suggested below, consider [`std::shuffle`](http://en.cppreference.com/w/cpp/algorithm/random_shuffle), which allows *you* to choose a prng rather than relying on the system's choice (which is often `rand()`, which just blows). – WhozCraig Feb 19 '14 at 10:42
  • This has possibly thousands duplicates. ;) – CouchDeveloper Feb 19 '14 at 10:55

5 Answers5

7

You may want to consider generating a simple sequence of integers 0,1,2,3,...(max value). Then you can shuffle() this sequence, using a proper pseudo-random number generator.

Note that rand() is considered harmful, and is discouraged in C++14.

See the following compilable commented code:

#include <algorithm>    // For std::shuffle
#include <iostream>     // For std::cout, std::endl
#include <random>       // For std::mt19937, std::random_device
#include <vector>       // For std::vector

int main()
{
    // Fill vector with numbers 0,1,2,3...,kMaxValue
    static const int kMaxValue = 7;
    std::vector<int> v(kMaxValue + 1);
    for (size_t i = 0; i < v.size(); ++i)
        v[i] = i;

    // Random seed generator
    std::random_device rd;

    // Psuedo random number generator
    std::mt19937 prng(rd());

    // Shuffle the 0,1,2,3...,kMaxValue integer sequence
    std::shuffle(v.begin(), v.end(), prng);

    // Print random sequence
    for (int x : v)
        std::cout << x << ' ';
    std::cout << std::endl;
}

Now, to apply this knowledge to your particular function, you can define a vector of unique (pseudo-random) integers are showed above.

Then, inside your code, you already have a loop with an index/counter named teamcounter, which goes from 0 to 7 (in fact, you have inside the while condition: ... && teamcounter < 8).
You can use this teamcounter as an index into the vector of unique integers. So, instead of doing:

int ran = rand()%8;

You can simply pick the pseudo-random integer from the vector:

int ran = vector_of_unique_pseudo_random_integers[teamcounter];
Mr.C64
  • 41,637
  • 14
  • 86
  • 162
6

See this example for std::shuffle from cppreference:

#include <random>
#include <algorithm>
#include <iterator>
#include <iostream>

int main()
{
    std::vector<int> v = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

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

    std::shuffle(v.begin(), v.end(), g);

    copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
    std::cout << "\n";
}

Example output:

4 1 7 0 3 6 9 2 8 5

You could also consider populating the vector using std::iota, which will scale to larger values more easily.

Also, as a general rule, prefer the facilities in <random> to rand(), which is crap (that's a technical term!). As WhozCraig points out, this actually uses std::shuffle, not std::random_shuffle. (Although if you are stuck in a pre-2011 world, you may have little choice).

To populate v with the same values using std::iota, you would do something like:

std::vector<int> v (10);
std::iota(std::begin(v), std::end(v), 1);
BoBTFish
  • 19,167
  • 3
  • 49
  • 76
  • 2
    +1 for *not* using `std::random_shuffle` =P – WhozCraig Feb 19 '14 at 10:42
  • @WhozCraig What's bad with `random_shuffle`? – CouchDeveloper Feb 19 '14 at 10:58
  • @CouchDeveloper See his comment on the question, and the link on MrC64's answer for why `rand()` sucks. – BoBTFish Feb 19 '14 at 11:00
  • @CouchDeveloper Its also being [proposed for deprecation](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3775.pdf) and with good reason. – WhozCraig Feb 19 '14 at 11:02
  • @WhozCraig I don't understand. What's bad with `std::rand`? EDIT: Ah, ok. will read that first ... – CouchDeveloper Feb 19 '14 at 11:02
  • @CouchDeveloper "See [...] the link on MrC64's answer for why rand() sucks." : http://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful – BoBTFish Feb 19 '14 at 11:04
  • @WhozCraig Well, the opposition to use rand() is justified for obvious reasons. However IMHO, there's no compelling reason to _commonly deprecate_ `random_shuffle`: the random generator used is still _implementation defined_. For example clang standard lib uses `uniform_int_distribution` in random_shuffle. – CouchDeveloper Feb 19 '14 at 11:32
  • @WhozCraig Also, the standard guarantees _"that each possible permutation of those elements has equal probability of appearance."_ . If that can't be guaranteed with an implementation using `rand()` wouldn't be that implementation incorrect? – CouchDeveloper Feb 19 '14 at 11:41
1

This is what you want: random_shuffle

MB-F
  • 22,770
  • 4
  • 61
  • 116
1

This is my logic to generate a random number within a range.

#define SIZE_MAX 8
int getRandom()
{
    static int iBuff[SIZE_MAX] = {0,1,2,3,4,5,6,7};
    static int iPivot = 0;

    int iPos = rand()%(SIZE_MAX-iPivot);

    int result= iBuff[iPos+iPivot];

    //
    // swap values at iPos and iPivot
    //
    int temp = iBuff[iPivot];
    iBuff[iPivot] = iBuff[iPos+iPivot];
    iBuff[iPos+iPivot] = temp;

    iPivot++;
    return result;
}
51k
  • 1,381
  • 3
  • 12
  • 22
0

You can save any number you get from the rand() % 8 to an array . Later when you can search the new number in the array to find it; if you found it you could generate a new number and if not you could use the new number.

  • Ngl This method was surprisingly faster than std::shuffle for some reason in a project that I was doing. Generate random numbers using rand() % count and check whether it exists in the unordered_set() (used to track it) and if not append it. This was about 3X faster than shuffle but i still ended up using the latter because ease of reading. – TheMedicineSeller Jul 11 '22 at 15:12