Random sorting within array

Jun 19, 2010 at 6:50pm
I have an array of std::strings I need to sort into random order. The thing is that no element can be repeated. To do this, I thought I would remove each element that is sorted out of the array, to keep it from repeating, but I don't know of any function to do that without just leaving a void in the array. Does anyone know of a way to do this?

Fafner
Jun 19, 2010 at 6:58pm
What do you mean "sort into random order"? That comes quite close to being contradiction if it isn't one already.

If you want to sort your strings and eliminate duplicates at the same time... why not an std::set? It automatically sorts any data put into it, and refuses to accept duplicates.
http://cplusplus.com/reference/stl/set/

Edit: if by sort into random order you mean mix up the values of the elements in your array randomly, then eliminate the duplicates first (you can do this by comparing the elements in your array with each other), then write a function that swaps the positions of two elements in the array.

-Albatross
Last edited on Jun 19, 2010 at 7:00pm
Jun 19, 2010 at 7:00pm
Well, for example, if I had the array 1, 2, 3, 4, 5, 6
Then I would want to have it sorted into, say, 3, 6, 4, 1, 5, 2

But thanks, I'll check out sets, I wasn't aware of them ;)
Jun 19, 2010 at 7:01pm
Ah... then check my edit in my other post. Note that you could use rand() to determine which elements to swap... but you knew that.

-Albatross

EDIT: std::cout << pow(2,0) << pow(2,1) << pow(2,2) << pow (2,3) << " posts, and counting.";
Last edited on Jun 19, 2010 at 7:17pm
Jun 19, 2010 at 7:06pm
haha, just saw your edit;)

Ok, so I tried to write a function, but naturally it segfaults=P If you would take a look it would be greatly appreciated:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Deck newShuffledDeck(void) {
	std::string values[] = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Knight", "Queen", "King"};
	std::string versions[] = {"Clubs", "Spades", "Hearts", "Diamonds"};
	Deck d;
	int vSize = 13;
	for (int i = 0; i < 3; i++) {
		for(int c = 0; c < 12; c++) {
			int vSel = rand()%vSize;
			Card c(values[rand()%vSel], versions[i]);
			for (int i = vSel; i < vSize; i++) {
				values[i] = values[i+1];
			}
			vSize--;
			d.push_back(c);
		}
	}
	return d;
}


As you can see, I'm trying to shuffle a deck of cards;)
Jun 19, 2010 at 7:14pm
Oh... so... oh... that's even easier.

First off, line 11 looks suspicious, but... it should work... egh, I recommend the use of vectors over arrays, because they have a function just for doing what you want to do.
http://cplusplus.com/reference/stl/vector/erase/

Second... maybe the problem is in your Deck? Again, if you're using arrays there, maybe you'd like to consider vectors.

EDIT:
Third... ooooh boy. Lines 7 and 9. Do you see the problem?
Fourth, the bounds for the for loop at line 6 are off. Do you see why?
Fifth, consider using j as the interated integer for the for loop starting at line 10.

-Albatross
Last edited on Jun 19, 2010 at 7:20pm
Jun 19, 2010 at 7:18pm
@Albatross
EDIT: std::cout << pow(2,0) << pow(2,1) << pow(2,2) << pow (2,3) << "posts, and counting.";

error C2668: 'pow' : ambiguous call to overloaded function :)
Jun 19, 2010 at 7:21pm
Great, thanks;) I tried vectors in the beginning though, and my compiler didn't like these lines:

1
2
std::vector<std::string> values = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Knight", "Queen", "King"};
std::vector<std::string> versions = {"Clubs", "Spades", "Hearts", "Diamonds"};


I could of course create each string and then push_back it, but is there a more efficient way?

EDIT: Haha, I just saw your last edit, that was stupid of me to name the int and card the same=P But why are the bounds at line 6 off? And Deck is just:
typedef std::vector<Card>Deck
And Card contains vectors;)
Last edited on Jun 19, 2010 at 7:25pm
Jun 19, 2010 at 7:25pm
@R0mai:
See, I don't get that error when compiling that line. I get the error
/Users/albatross/Documents/testpad/main.cpp:1:0 /Users/albatross/Documents/testpad2/main.cpp:1: error: 
expected constructor, destructor, or type conversion before '<<' token


@fafner:
You go through only three of the versions, and that's why the bounds are off. Did you mean i <= 3?
And the shorter (textwise) way is to create an extra array with those values, and use assign(). There's probably a shorter way but my brain is running low on caffeine.

http://cplusplus.com/reference/stl/vector/assign/

Note the third comment on the code snippet.

-Albatross
Last edited on Jun 19, 2010 at 7:31pm
Jun 19, 2010 at 7:29pm
@Albatross
OK, call it even, it doesn't compile either way :)
Jun 19, 2010 at 8:11pm
In order to do this:

std::vector<std::string> values = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Knight", "Queen", "King"};

You could do this:

1
2
3
4
5
6
7
const char* card_data[] =
{
	"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10"
	, "Knight", "Queen", "King"
};

std::vector<std::string> card_list(card_data, card_data + (sizeof(card_data)/sizeof(char*)));
Jun 19, 2010 at 8:38pm
Thanks for all your help folks! My code currently looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Deck newShuffledDeck(void) {
	srand(clock());
	std::string vals[] = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
	std::string vers[] = {"Clubs", "Spades", "Hearts", "Diamonds"};
	std::vector<std::string> values;
	std::vector<std::string> versions;
	values.assign(vals, vals+13);
	versions.assign(vers, vers+4);
	Deck d;
	for (int i = 0; i < 4; i++) {
		for(int j = 0; j < 13; j++) {
			int vSel = rand()%values.size();  //this is problematic!!
			Card c(values[vSel], versions[i]);
			values.erase(values.begin()+vSel);
			d.push_back(c);
		}
	}
	return d;
}


The program compiles but crashes immediately. My IDE tells me that the line marked above is the culprit, which doesn't really make sense to me. Any clues?
Jun 19, 2010 at 9:57pm
Jun 20, 2010 at 7:14pm
Awesome, thanks everyone!
Jun 22, 2010 at 1:57am
I'd also recommend using a struct to define a card. It'll be a lot easier to maintain the deck and it'll be more object oriented since you would normally think of each card as being one "thing".

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Make one instance for each card
struct card
{
   string value;
   string suit;
};

// use c-array or some container type like std::vector or std::deque
const int NUMCARDS(52);
card theDeck[NUMCARDS];
// I'm sure that you can figure out how to insert all 52 cards now.

// to shuffle
std::random_shuffle(theDeck, theDeck + NUMCARDS);
Topic archived. No new replies allowed.