2

I would like to generate list of strings with no repeats as follows

A1, A2 , A3 , A4 , B1 , B2 , B3 , B4 , C1, C2, C3, C4

this is the way I generate out my list of strings

std::string columns[] ={"A","B","C"};
std::string rows[]={"1","2","3","4"};
std::string columnsAndRows;

for(int i=0; i<10; i++) {
    for(int j=0; j<10; j++) {
        columnsAndRows=columns[i]+row[j];
        //possible to do something like this?
        columnAndRows.rand();
    }
}

but the problem is, I read about rand() and it returns a pseudo-random integral number in the range between 0 and RAND_MAX. what should I do to generate a random string base on my desired requirements?

8
  • You can 'map' rand() results using the modulus function to your specific ranges. Commented Nov 17, 2013 at 14:51
  • for(int j=0; j=10; j++) Should be for(int j=0; j==10; j++). The first one is assigning and not comparing. Commented Nov 17, 2013 at 14:52
  • I don't see what that code, or the example output you posted, has to do with randomness. Do you mean that you want to choose one of those two-character strings at random? Commented Nov 17, 2013 at 14:52
  • It also has the nasty side effect that the loop will not be looped. Commented Nov 17, 2013 at 14:52
  • 2
    You can simply construct the "list" A1, A2, ... and then std::random_shuffle it. Be aware that random_shuffle uses rand by default, which is a) not very good (use C++11's PRNGs if possible) and b) requires seeding by srand. Commented Nov 17, 2013 at 14:57

6 Answers 6

4

Using std::rand with the modulus might not be a good idea. Instead you can easily construct a std::vector of possible elements and do a std::random_shuffle on that container:

std::vector<std::string> cols = {"A", "B", "C"};
std::vector<std::string> rows = {"1", "2", "3", "4"};
std::vector<std::string> vec;
for (auto i : cols)
    for (auto j : rows)
        vec.emplace_back(i + j);
std::random_shuffle(vec.begin(), vec.end());

And here's the running code results.


As hinted by DyP, std::random_shuffle might use rand inside its implementation (the truth is that it's implementation defined) therefore you might incur in the problem of keep getting the same results over and over again because you did not seed the random function.

Thankfully C++11 introduces std::shuffle that allow us to pass a third argument and define our own random generator functor. The great thing about this is that we can easily use <random> to feed that argument:

std::mt19937 rand_func(std::random_device{}());
std::shuffle(vec.begin(), vec.end(), rand_func);

And here's the running code results.

Sign up to request clarification or add additional context in comments.

2 Comments

Don't forget the seeding ;)
"the truth that it's implementation defined" Ah! Good catch - I didn't even bother looking it up because of the C++11 facilities ;D
1

So why can't you use rand()? Because it may return a too-large value? Then pick a random value and if it's too large, (a) don't use it but pick another or (b) clip off the too large part using the % (modulus) operator:

my1stOwnRandomValue = rand() % 4;
my2ndOwnRandomValue = rand() % 4;
columnsAndRows=columns[my1stOwnRandomValue]+rows[my2ndOwnRandomValue];

This does not address "with no repeats", to do so you need more code. You may keep a list of 'used' values, or create a list of all possible combinations (after all there are only 16) and pick one at random from this list, then remove the picked combination from the list.

2 Comments

As an alternative to generating random strings you could generate the list and shuffle it.
Indeed, since the OP wants to avoid repeats that's preferable. I said "it needs more code" but all it needs is a bit of C++.
1

you can use time as the seed of random function this can aviod pseudo-random

srand((unsigned) time(NULL)); /*set seed must #include <time.h>*/
for(int i=0; i<10; i++) {
    for(int j=0; j<10; j++) {
      columnValue=rand() % 4;
      rowValue=rand() % 4;
      columnsAndRows=columns[columnValue]+row[rowValue];
    }
}

Comments

1

Here's a C++11 version:

#include <random>
#include <algorithm>
#include <iostream>
#include <cstddef>
#include <vector>

// helper to get the size (extent) of a raw array
template<class T, std::size_t N>
constexpr std::size_t get_extent(T&)
{  return std::extent<T>::value;  }

int main()
{
    std::string const chars[] = {"A","B","C"};
    std::string const digits[] = {"1","2","3","4"};

    // vector containing the resulting strings
    std::vector<std::string> result;

    // create the "ordered" sequence A1, A2, A3, A4, B1, ..
    for(auto const& eChar : chars)
        for(auto const& eDigit : digits)
            result.push_back( eChar+eDigit );

    // shuffle the sequence
    {
        // random device to seed the PRNG
        std::random_device rd;
        // create a MT19937 PRNG, seeded
        std::mt19937 g(rd());

        std::shuffle(begin(result), end(result), g);
    }

    // output result
    for(auto const& e : result) std::cout << e << ", ";
    std::cout << "\n";
}

A C++03 version:

#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <cstddef>
#include <vector>

// helper to get the size (extent) of a raw array
template<class T, std::size_t N>
std::size_t get_extent(T (&)[N])
{  return N;  }

int main()
{
    std::string const chars[] = {"A","B","C"};
    std::string const digits[] = {"1","2","3","4"};

    // vector containing the resulting strings
    typedef std::vector<std::string> result_t;
    result_t result;

    // create the "ordered" sequence A1, A2, A3, A4, B1, ..
    for(std::string const* pChar = chars;
        pChar != chars + get_extent(chars);
        ++pChar)
        for(std::string const* pDigit = digits;
            pDigit != digits + get_extent(digits);
            ++pDigit)
            result.push_back( *pChar+*pDigit );

    // shuffle the sequence
    {
        std::srand( std::time(NULL) );
        std::random_shuffle(result.begin(), result.end());
    }

    // output result
    std::copy(result.begin(), result.end(),
              std::ostream_iterator<std::string>(std::cout, ", "));
    std::cout << "\n";
}

Comments

0
string strcat1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string strcat2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int stringl1 = strcat1.size() - 1;
int stringl2 = strcat1.size() - 1;
auto strfn1 = [&]() {return strcat2[rand() % stringl2];}; //will return a single char
auto strfn2 = [&]() {return strcat2[rand() % stringl2];};
while (true)
{
    this_thread::sleep_for(500ms);

    std::string str1(1, strfn1()); //fill 1 string/char space with arg2 here strfn1
    std::string str2(1, strfn2());
    std::string str3(1, strfn2());
    str1 += str2;
    str1 = str3 + str2 + str1 + str3; //as many adjacent string as you want
    cout << str1<<" ";
}

Comments

0

@Jongware

You can avoid generating a number larger than the provided range by using the minimum and the difference between the maximum and minimum range instead.

So rather than:

int x = rand() % max + min;

Use:

int diff = max - min;

int x = rand() % diff + min;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.