This code picks a random color from a array of pre-set colors. How do I make it so the same color doesn't get picked more than once?
var colorArray = [(UIColor.redColor(), "red"), (UIColor.greenColor(), "green"), (UIColor.blueColor(), "blue"), (UIColor.yellowColor(), "yellow"), (UIColor.orangeColor(), "orange"), (UIColor.lightGrayColor(), "grey")]
var random = { () -> Int in
return Int(arc4random_uniform(UInt32(colorArray.count)))
} // makes random number, you can make it more reusable
var (sourceColor, sourceName) = (colorArray[random()])
One case, described here: https://github.com/dimpiax/GenericSequenceType
Another is functional:
based on the fact, that arc4random_uniform generate not only random, but also uniformly distributed numbers
simple test for different k and stream length of one milion
prints
finaly, here is more Swifty and functional approach based on the same idea
Create an array of indexes. Remove one of the indexes from the array and then use that to fetch a color.
Something like this:
The code above creates an array
indexes
. The functionrandomItem
looks to see ifindexes
is empty. if it is, it populates it with index values ranging from 0 tocolorArray.count - 1
.It then picks a random index in the
indexes
array, removes the value at that index in theindexes
array, and uses it to fetch and return an object from yourcolorArray
. (It doesn't remove objects from thecolorArray
. It uses indirection, and removes objects from the indexesArray, which initially contains an index value for each entry in yourcolorArray
.The one flaw in the above is that after you fetch the last item from indexArray, you populate it with a full set of indexes, and it's possible that the next color you get from the newly repopulated array will be the same as the last one you got.
It's possible to add extra logic to prevent this.
How about running a while loop with the condition:
This will keep looping until a new random color has been selected.
edit
Additional Note: The point was the while loop. There are ways to safeguard from an infinite loop, it's up to the coder to find the right solution. I don't think SO is a place to write other's code but instead to offer suggestions .. mine is a start.
But since my answer was given such a negative rating, i'll push instead of nudge in the right direction.
The other answers are unnecessarily bloated. And? The one I offered above offers a less than desirable time complexity. So, here's my new answer (in meta code):
Fill an array with the colors and shuffle it with a Fisher-Yates shuffle. Then use the element at an end, remove it, and insert it at a random position at least n positions from the end.
For example, say my array has 10 elements. I shuffle it and take the last. I want at least 2 values to be chosen before I see it again so I generate a random position in the range
0...8
and insert it there.