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?
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.
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.
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];
}
}
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";
}
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<<" ";
}
#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;
Related
For example:
If I end up with multiple digits and all of those numbers are generated randomly (1-9) up to 7 digits total and I want them all to end up as a whole integer, how do I go by doing this?
Here is something I have tried:
static void generate_key(std::map<std::string, int>& key, std::string c_user)
{
unsigned int hold[7]{}; // will hold all the random integers seperate to add onto final
int *final = new int; // will store a complete 7 digit integer here later on
for (int i = 0; i < 7; i++)
{
unsigned int num = rand() % 9;
hold[i] = num;
}
*final = hold[0] + hold[1] + hold[2] + hold[3]; // I know this sums everything but how do I get it to just add all the numbers into a single integer?!
key.emplace(c_user, final);
std::cout << "Key created: " << *final << '\n';
delete final;
}
Hold all integers seperate from eachother:
unsigned int hold[7]{};
Create random digits:
for (int i = 0; i < 7; i++)
{
unsigned int num = rand() % 9;
hold[i] = num;
}
Store and add all integers into *final integer
int *final = new int;
I want to generate a 7 digit key and each of every single digit is randomized. I then want to add them all up to make a whole integer that gets put into a map where a string has already been created and that key will represent the string. Do you get what I'm saying here? Sorry if my explanation is terrible I'm just too lost here..
Here is the full code if thats helpful:
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <stdlib.h>
class Account
{
private:
std::string username;
std::string password;
public:
Account(std::string username, std::string password)
{
this->username = username;
this->password = password;
}
~Account() {};
std::string get_username()const { return username; }
std::string get_password()const { return password; }
};
static void create_account(std::string user, std::string pass, std::vector<Account> &acc)
{
Account *account = new Account(user, pass);
acc.push_back(*account);
delete account;
}
static void generate_key(std::map<std::string, int>& key, std::string c_user)
{
unsigned int hold[7]{};
int *final = new int;
for (int i = 0; i < 7; i++)
{
unsigned int num = rand() % 9;
hold[i] = num;
}
*final = hold[0] + hold[1] + hold[2] + hold[3];
key.emplace(c_user, final);
std::cout << "Key created: " << *final << '\n';
delete final;
}
std::vector<Account> accounts;
std::map<std::string, int> keys;
int main()
{
srand(time(NULL));
create_account("random", "triathlon", accounts);
generate_key(keys, accounts[0].get_username());
return 0;
}
static void create_account(std::string, std::string, std::vector<Account> &acc);
static void generate_key(std::map<std::string, int>&, std::string);
If you want to generate a 7 digit number where all of the digits are unique, then you can store the valid digits in a vector and then shuffle that vector and take the first 7 elements as the digit to make the number with. That could be done like:
std::vector<char> digits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}
std::random_device rd;
std::mt19937 g(rd());
std::suffle(digits.being(), digits.end(), g);
std::string number{digits.begin(), digits.begin() + 7}
and now number is a 7 digit string where each digit only appears once. If you want to not have a leading zero, then you would need to check if the first element is a zero and if so, shuffle again or just takes elements 1 through 7.
If you just want to generate a 7 digit number, but you don't care if there are duplicate digits, then you can do that with a std::string and a simple for loop like:
std::random_device rd;
std::mt19937 g(rd());
std::uniform_int_distribution<> dist(0, 9);
std::string number;
for (int i = 0; i < 7; ++i)
{
number.push_back('0' + dist(g))
}
If you just want a random seven digit number with unique digits you can generate that directly using the typical random shuffle algorithm where you generate a random index into an array take that item, swap the back of the array with it, and pop back of the array.
I forget what this algorithm is called.
In your case you only need to do seven iterations starting with the nine digits. Code below:
#include <vector>
#include <array>
#include <algorithm>
#include <iostream>
int remove_rnd_item( std::vector<int>& digits ) {
int n = rand() % digits.size(); // should use a better RNG...
int rnd_digit = digits[n];
//swap with the last digit and pop...
std::swap(digits[n], digits.back());
digits.pop_back();
return rnd_digit;
}
int random_seven_digit_number_with_unique_digits() {
std::vector<int> digits = { 0,1,2,3,4,5,6,7,8,9 };
std::array<int, 7> rnd_digits;
std::generate(rnd_digits.begin(), rnd_digits.end(),
[&digits]() {
return remove_rnd_item(digits);
}
);
// convert the digits vector to a single int, if that is what you want
int tens_place = 1;
int val = 0;
for (auto digit : rnd_digits) {
val += tens_place * digit;
tens_place *= 10;
}
return val;
}
int main() {
for (int i = 0; i < 10; ++i) {
std::cout << random_seven_digit_number_with_unique_digits() << "\n";
}
}
I assume that the requirement to have all unique digits in the customer ID is erroneous.
To get a random 7-digit number you only need:
#include <random>
#include <iostream>
int main()
{
std::random_device rd; //Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); //Standard mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<> distrib(0, 9'999'999);
std::cout << distrib(gen) << std::endl;
}
If you want to avoid leading zeroes, use distrib(1'000'000, 9'999'999);
Weeee! Hi!.I'm a beginner too!. and yeah. I think you can do that like this!.
int boop(){
int ding=1000000;
int a[7]={1,4,6,3,4,2,4};
int re=0;
for(int i=0;i<7;i++){
re+=a[i]*ding;
ding/=10;
}
return re;
}
or just make your own function to make a random number ranging from 0 to 1. and multiply it with 9999999. (kinda recommended).
#include <iostream>
#include <math.h>
float boop(int seed){
return abs(sin( cos(seed*3972)*38472));
}
int main(){
float f=boop(34)*9999999;
std::cout<<(int)f;
return 0;
}
I need to generate random strings efficiently. In the following, you will see my first try. I compiled the code with gcc and -O3 optimization level. It takes 18.5 seconds to generate 10^7 random strings of length 64:
#include <iostream>
#include <random>
#include <algorithm>
std::string chars {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!##$%^&*()`~-_=+[{]{|;:'\",<.>/?"};
std::random_device rd;
std::mt19937 generator(rd());
std::string rand_str (int length) {
std::string output (chars);
std::shuffle(output.begin(), output.end(), generator);
return output.substr(0, length);
}
int main() {
std::string str;
for (long i=0; i<10000000; ++i)
str = rand_str (64);
}
I checked std::sample in c++17 and it is not faster than the above method. In addition, it will not change the order of characters and so it is not really random.
Edit: The std::shuffle is not a good choice, since, it will not allow duplicates. Based on comments I modified the code. This time it takes more than 9 minutes for 10^7 random numbers.
std::string rand_str (size_t length) {
const size_t char_size = chars.size();
std::uniform_int_distribution<> random_int (0, char_size - 1);
std::string output;
for (size_t i=0; i<length; ++i)
output.push_back(chars[random_int(generator)]);
return output;
}
Question
Are there more efficient ways to do this in modern C++?
I appreciate any suggestions to improve the code.
#include <iostream>
#include <random>
#include <algorithm>
#include <chrono>
std::string chars {"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!##$%^&*()`~-_=+[{]{|;:'\",<.>/?"};
std::random_device rd;
std::mt19937 generator(rd());
std::string rand_str(int length) {
std::string output;
output.reserve(length);
while(length>0)
{
auto randNumb = generator();
while(randNumb > 93 && length--)
{
output.push_back(chars[randNumb%93]);
randNumb/=93;
}
}
return output;
}
int main() {
auto startTP = std::chrono::system_clock::now();
std::string rand_bytes;
for (long i=0; i<10000000; ++i)
rand_bytes = std::move(rand_str(64));
auto endTP = std::chrono::system_clock::now();
std::cout << "This took: " << std::chrono::duration_cast<std::chrono::microseconds>(endTP-startTP).count() << std::endl;
}
This takes around 3 seconds on my machine. The trick is to call the random number generator as little as possible and to allocate the memory only once.
What I'm doing is converting randNumber from base 10 to base 93(the length of chars). After that im using every base 93 digit as a different random number. This provides around 5 numbers per generated random number.
I wanted to try the C++ random number generator but couldn't seem to obtain very satisfying results. For example here is an attempt among others to create a random string of characters.
#include <iostream>
#include <string>
#include <random>
std::string f(unsigned int n){
std::uniform_int_distribution<int> dis025(0, 25);
std::mt19937 gen_mt(n);
std::string str(5, '\0');
for(int i = 0; i<5; i++)
str[i] = (char)('a' + dis025(gen_mt));
return str;
}
int g(unsigned int n, int m){
std::uniform_int_distribution<int> dis(0, m);
std::mt19937 gen_mt(n);
return dis(gen_mt);
}
int main() {
std::string s = f(g(106175305, 40000000)) + " " + f(g(53718209, 40000000));
std::cout << "Random string: " << s << std::endl;
}
Link to Coliru.
(I had to use the f(g()) trick so that it stops shouting insults.)
It is quite annoying and I doubt that is the desired behavior. But somehow I am helpless to prevent it, it keeps happening, again...
#include <iostream>
#include <string>
#include <random>
std::string fx(unsigned int n, int m){
std::uniform_int_distribution<int> dis(0, m);
std::mt19937 gen_mt(n);
std::string str(6, '\0');
for(int i = 0; i<6; i++)
str[i] = (char)('.' + dis(gen_mt));
return str;
}
int g(unsigned int n, int m){
std::uniform_int_distribution<int> dis(0, m);
std::mt19937 gen_mt(n);
return dis(gen_mt);
}
int main() {
std::string s1 = fx(g(66730461, 90000000) + 400000000, 33) + "/" + fx(g(28989020, 90000000) * 10, 43);
std::cout << s1 << std::endl;
}
Coliru.
...and again.
int main() {
std::string s2 = fx(g(66730461, 90000000) + 400000000, 33) + "/" + fx(g(81141643, 90000000) + 100000000, 43);
std::cout << s2 << std::endl;
}
Do you often meet that kind of problem? or am I especially unlucky?
My sad friend, I must inform you that in all my life I have never encountered a programmer with as poor luck as you have. The chances of a random string generator creating human-readable output is one in a million, but you managed to do it three times in a row (one in a trillion?)
In all honesty, the trick was quite clever. May your future endeavors be more predictable :)
(Future readers: The results were generated using hand-picked pseudo-random seed values that happened to output specific strings, like "hello world", etc... Check out the comments on the question for more info)
I would like to know if there is already an implementation in CPP to find all permutations of n characters of length k(1,2,3,4 etc) with repetitions. I hope there is but i could not find.
For example if string= (A,B,C,D) and i want find all permutations of string with repetitions of length k =2.
The output will be something like :
AA
AB
AC
AD
.
.
.
DD
total permutations of 16.
Simple recursive solution which will work for you for sure.
Let me first re-write your specification: Print all permutations with repetition of characters
Given a string of length n, print all permutation of the given string.
Repetition of characters is allowed
For a given string of size n, there will be n^k possible strings of length "length". The idea is to start from an empty output string (we call it prefix in following code). One by one add all characters to prefix. For every character added, print all possible strings with current prefix by recursively calling for "length" equals to "length"-1.
#include <string>
#include <iostream>
void print_str(const char*,std::string,const int, const int);
int main()
{
int lenght = 2;
char str[] = {'A', 'B', 'C', 'D'};
int n = sizeof str;
print_str(str, "", n, lenght); //Note: this function works on all cases and not just the case above
return 0;
}
// The main recursive method to print all possible strings of length "length"
void print_str(const char str[],std::string prefix,const int n, const int lenght)
{
if (lenght == 1)
{
for (int j = 0; j < n; j++)
std::cout << prefix + str[j] << std::endl;
}//Base case: lenght = 1, print the string "lenght" times + the remaining letter
else
{
// One by one add all characters from "str" and recursively call for "lenght" equals to "lenght"-1
for (int i = 0; i < n; i++)
// Next character of input added
print_str(str, prefix + str[i], n, lenght - 1);
// "lenght" is decreased, because we have added a new character
}
}
Here is the execution of the code above:
References:
http://www.geeksforgeeks.org/print-all-permutations-with-repetition-of-characters/
http://www.geeksforgeeks.org/print-all-combinations-of-given-length/
Update: this update is writen answring the following spec.
I need one more help!! as i am new to CPP programming. Suppose if
length = 3 how can i make it to get all permutations starting from
length = 1 to length = 3 together in an array. Means to get all the
permutations of length =1, length =2 and length = 3 together stored in
an array
#include <string>
#include <iostream>
#include <vector>
void print_str(const char*,std::string,const int, const int);
std::vector<std::string> permutations ; // the vector permutations which will hold all the permutations,
//if you want you can use it for later use or you can use the array below which is nothing than a copy of this vector.
int NumberOfPermutations = 0; // this variable holds the number of permutations
int main()
{
int lenght = 3;
char str[] = {'A', 'B', 'C', 'D'};
int n = sizeof str;
//here we loop through all the possible lenghts 1, 2 and 3
for (int k = 1; k <= lenght; k++)
{
print_str(str, "", n, k); //Note: this function works on all cases and not just the case above
}
std::string* permut_array = new std::string[NumberOfPermutations]; // the array that we will use to store the permutations in
std::copy(permutations.begin(), permutations.end(), permut_array); // here we copy the vector into the array
//if you want you can use your array to print the permutation as folow
for (int k = 0; k < NumberOfPermutations; k++)
{
std::cout << permut_array[k] << std::endl;
}
return 0;
}
// The main recursive method to print all possible strings of length "length"
void print_str(const char str[],std::string prefix,const int n, const int lenght)
{
if (lenght == 1)
{
for (int j = 0; j < n; j++)
{
// i commented this ligne so that if you want to use your array to print your permutations you will not get a screnn with permutations printed 2 times
//std::cout << prefix + str[j] << std::endl;
permutations.push_back(prefix + str[j]); // the vector that we will use to store the permutations in
}
}//Base case: lenght = 1, print the string "lenght" times + the remaining letter
else
{
// One by one add all characters from "str" and recursively call for "lenght" equals to "lenght"-1
for (int i = 0; i < n; i++)
// Next character of input added
print_str(str, prefix + str[i], n, lenght - 1);
// "lenght" is decreased, because we have added a new character
}
NumberOfPermutations = permutations.size();
}
you can use std::next_permutation() as πάντα ῥεῖ said, but since you want to define the length and the char with repetitions, you can do something easy to realize it, as:
std::string s = "aabbccdd";
std::set<std::string> string_set;
std::sort(s.begin(), s.end());
do {
string_set.insert(s.substr(0, 2));
} while(std::next_permutation(s.begin(), s.end()));
for(auto i = string_set.begin(); i != string_set.end(); ++i)
std::cout << *i << std::endl;
This just isn't a permutation, which probably explains why you can't find an answer.
What you are actually asking is how to print the numbers 0..k-1 in base n, using digits A,B,C,D. I'll rewrite your example with familiar digits 0,1,2,3 :
00
01
02
03
10
11
12
13
..
33
There's no standard C++ method for this, but now that you know what it's called there's plenty of code on the web. Or just write it yourself. Hint: the last digit of i has value i % n.
This solution works out for all standard container and also static arrays. I think this can be used also for classes and structures
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <list>
#include <iterator>
template<typename InputIt, typename T>
bool nextPermutationWithRepetition(InputIt begin, InputIt end, T from_value, T to_value) {
auto it = std::find_if_not(std::make_reverse_iterator(end),
std::make_reverse_iterator(begin),
[&to_value](auto current) { return to_value == current; });
if (it == std::make_reverse_iterator(begin))
return false;
auto bound_element_iterator = std::prev(it.base());
(*bound_element_iterator)++;
std::fill(std::next(bound_element_iterator), end, from_value);
return true;
}
int main() {
std::list<int> vec(3, 0);
do {
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl;
} while (nextPermutationWithRepetition(vec.begin(), vec.end(), 0, 2));
return 0;
}
I have a hand full of objects each containing several strings each. Right now its set up as structures each containing a map with keys 1...n, one for each string (map<int,string> strs), this can be changed if a better way exists. I need to randomly access all of these str ings without overlapping and know that i'm done. How can I do this, either with the maps or another data structure? Thanks.
Here's some code for a Fisher-Yates shuffle:
template <class T>
std::vector<T> shuffle(std::vector<T> &vect)
{
std::vector<T> shuffled = vect;
for(int i = shuffled.size()-1; i >= 1; i--) {
int idx = rand() % (i+1);
T tmp = shuffled[idx];
shuffled[idx] = shuffled[i];
shuffled[i] = tmp;
}
return shuffled;
}
This will take in a vector, and return a copy of it in a random order. If you have a vector of strings, you can use it like this (I'm using c++11 here):
int main()
{
srand(time(NULL));
std::vector<std::string> strs = {"foo", "bar", "baz", "stack", "overflow"};
for(auto &str : shuffle(strs)) {
std::cout << str << std::endl;
}
return 0;
}
Of course, if you're lazy, like me, there's always the random_shuffle() function in <algorithm>:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
int main()
{
std::vector<std::string> strs = {"foo", "bar", "baz", "stack", "overflow"};
std::random_device rd;
std::mt19937 g(rd()); // Use a good random number generaor
std::random_shuffle(strs.begin(), strs.end(), g); // this does the shuffle
for(auto &str : strs) {
std::cout << str << std::endl;
}
return 0;
}
Hope this helps!
A horrible solution, don't do this. Very slow for large candidate vectors, this has n-squared complexity. Shuffling is better, it has linear complexity.
std::vector<int> RandomThing(int number, int min, int max)
{
assert(!"RandomThing" && min < max);
std::vector<int> candidates;
for(int i=min; i<max; i++)
candidates.push_back(i);
std::vector<int> result;
for(int i=0; i<number;)
{
int candidate_index = rand() % candidates.size();
result.push_back(candidates[candidate_index]);
std::vector<int>::iterator it = candidates.begin();
std::advance(it, candidate_index);
candidates.erase(it);
}
return result;
}