0

I need to pick m amount of random characters(letters) without repetition and im completely stuck, i keep getting only 1 random letter. How can i fix my code? Is there even a way to fix this or should i just scrap this idea and look for a solution from some kinf od tutorials?

#include <iostream> #include <ctime> #include <cstdlib> #include <string> using namespace std; int main() { cout << "number below 27" << endl; int m; cin >> m; srand(time(NULL)); bool repeat = false; char letters[m]; char letter; for(int i = 0; i < m; i++){ letter = rand()%26 +97; repeat = true; for(int j = 0; j < m; j++){ if(letters[m] == letters[j]){ repeat = false; break; } } if(repeat){ letters[m] = letter; } } for (int i = 0; i < m; i++){ cout << letters[m]; } } 
5

4 Answers 4

3

You can use suffle -

#include <random> #include <iostream> #include <algorithm> #include <vector> using namespace std; int main () { char charSet[]={'a','b','c'};//You can add all the charecters std::random_device rd; std::mt19937 g(rd()); std::shuffle(charSet,charSet+3,g); for(auto c : charSet) { std::cout<<c; } std::cout<<endl; return 0; } 
Sign up to request clarification or add additional context in comments.

Comments

0
bool repeat = false; vector<char> letters(m); char letter; for(int i = 0; i < m; i++){ do { repeat = false; letter = rand()%26 +97; // generate new random number for(int j = 0; j<=i; j++) // iterate through the already generated numbers { if (letter == letters[j]){ // if the generated number already exists, do the while again repeat = true; break; } } } while(repeat); letters[i] = letter; // assign the unique number cout << letter; repeat = false; } 

You repeat the random number generator until you have a unique random number. And to output your values use i because m is constant and out of bounds:

for (int i = 0; i < m; i++){ cout << letters[i]; } 

2 Comments

I think im gonna stick to this solution, thank you, that makes sense!
@BigPaws You're welcome. An upvote or accept would be nice if this is the answer of your choice ;)
0

I think the direct method is to use set in C++. The following solution is done just now utilising set to ensure the unique. Hope it could be helpful.

#include <iostream> #include <ctime> #include <set> #include <random> using namespace std; int main() { cout << "number below 27" << endl; int m; cin >> m; srand(time(NULL)); set<char> letters_set; while(letters_set.size() < m){ char c = rand()%26+'a'; letters_set.insert(c); } for(auto c: letters_set) cout<<c<<endl; } 

A more efficient solution which also ensure the equal possibility for each letter.

#include <iostream> #include <ctime> #include <set> #include <random> using namespace std; int main() { cout << "number below 27" << endl; int m; cin >> m; srand(time(NULL)); vector<int> all_letters(26, 'a'); for(int i = 0; i < 26; ++i) all_letters[i] += i; vector<char> letters_set; for(int i = 0; i < m; ++i){ int select = rand()%all_letters.size(); letters_set.push_back(all_letters[select]); all_letters.erase(all_letters.begin()+select); } for(auto c: letters_set) cout<<c<<endl; } 

5 Comments

How does this avoid repetition?
@walter: with the std::set, but then the order is fixed and not random.
@Walter the first solution is using set to avoid repetition but it's quite inefficient since there will be lots of collision which could be further avoided as the second solution does.
@Hearen: In the second solution, you can easily remove the set by just removing 26 - m random letters from all_letters.
I dont think my professor would be satisfied with me using this answer, since its not something we used during classes. But thanks, now i definitely want to test this solution too!
0

There is an obvious error in the logic of your code: when you test for repetition you compare to the beyond the end letter only, instead to all those sampled so far. The correct test would be

 for(int i = 0; i < m; i++) { bool repeating; char tryletter; do { tryletter = rand()%26 +97; repeating = false; for(auto j=0; j!=i && !repeating; ++j) repeating = tryletter == letters[j]; } while(repeating); letters[i] = tryletter; } 

Though this is not the most efficient way to do what you've been asked to do. A more efficient way would be to start with all 26 letters, pick one at random and remove it from the set, then continue to pick and remove random letters. For example

std::string random_letters_without_repetition(std::size_t m) { std::string letters; std::string all = "abcdefghijklmnopqrstuvwxyz"; assert(m <= all.size()); std::random_device r; std::default_random_engine rng(r()); while(m--) { std::uniform_int_distribution<std::size_t> uni{0,all.size()-1}; auto index = uni(rng); letters += all[index]; all.erase(index); } return letters; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.