Randomly Choosing an Item from a Swift Array Without Repeating

Randomly choosing an item from a Swift array without repeating

Create an array of indexes. Remove one of the indexes from the array and then use that to fetch a color.

Something like this:

var colorArray = [
(UIColor.redColor(), "red"),
(UIColor.greenColor(), "green"),
(UIColor.blueColor(), "blue"),
(UIColor.yellowColor(), "yellow"),
(UIColor.orangeColor(), "orange"),
(UIColor.lightGrayColor(), "grey")]

var indexes = [Int]();

func randomItem() -> UIColor
{
if indexes.count == 0
{
print("Filling indexes array")
indexes = Array(0..< colorArray.count)
}
let randomIndex = Int(arc4random_uniform(UInt32(indexes.count)))
let anIndex = indexes.removeAtIndex(randomIndex)
return colorArray[anIndex].0;
}

The code above creates an array indexes. The function randomItem looks to see if indexes is empty. if it is, it populates it with index values ranging from 0 to colorArray.count - 1.

It then picks a random index in the indexes array, removes the value at that index in the indexes array, and uses it to fetch and return an object from your colorArray. (It doesn't remove objects from the colorArray. It uses indirection, and removes objects from the indexesArray, which initially contains an index value for each entry in your colorArray.

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 to generate a single random item from array without a repeat?]

you can add an array of seen index like below and get the random values each time until all array items are fetched randomly. You will get the Idea from this and implement your own way to do it properly as you desire

 //The lists of items
let items = ["blue","red","purple", "gold", "yellow", "orange","light blue", "green", "pink", "white", "black"]

//array to hold the index we have already traversed
var seenIndex = [Int]()

func chooseRandom() -> String {

if seenIndex.count == items.count { return "" } //we don't want to process if we have all items accounted for (Can handle this somewhere else)

let index = Int(arc4random_uniform(UInt32(items.count))) //get the random index

//check if this index is already seen by us
if seenIndex.contains(index) {
return chooseRandom() //repeat
}

//if not we get the element out and add that index to seen
let requiredItem = items[index]
seenIndex.append(index)
return requiredItem
}

Another approach is listed below. This will also give you random/unique values but without using recursion

var items = ["blue","red","purple", "gold", "yellow", "orange","light blue", "green", "pink", "white", "black"]

//This will hold the count of items we have already displayed
var counter = 0

func ShowWord() {

//we need to end if all the values have been selected
guard counter != items.count else {
print("All items have been selected randomly")
return
}

//if some items are remaining
let index = Int(arc4random_uniform(UInt32(items.count) - UInt32(counter)) + UInt32(counter))

//set the value
randomWord?.text = items[index]

//printing for test
debugPrint(items[index])

//swap at the place, so that the array is changed and we can do next index from that index
items.swapAt(index, counter)

//increase the counter
counter += 1

}

Yet another way would be to take advantage of swap function. The following things are happening here

1. We create a variable to know how many items we have selected/displayed from the list i.e var counter = 0

2. If we have selected all the elements then we simply return from the method

3. When you click the button to select a random value, we first get the random index in the range from 0 to array count

4. Set the random item to randomWord i.e display or do what is intended

5. now we swap the element
e.g if your array was ["red", "green", "blue"] and the index was 2 we swap "red" and "blue"

6. Increase the counter

7. when we repeat the process the new array will be ["blue", "green", "red"]

8. The index will be selected between _counter_ to _Array Count_

Randomly select 5 elements from an array list without repeating an element

You can do it like this:

let array1 = ["salmon", "turkey", "salad", "curry", "sushi", "pizza", "curry", "sushi", "pizza"]
var resultSet = Set<String>()

while resultSet.count < 5 {
let randomIndex = Int(arc4random_uniform(UInt32(array1.count)))
resultSet.insert(array1[randomIndex])
}

let resultArray = Array(resultSet)

print(resultArray)

A set can contain unique elements only, so it can't have the same element more than once.

I created an empty set, then as long as the array contains less than 5 elements (the number you chose), I iterated and added a random element to the set.

In the last step, we need to convert the set to an array to get the array that you want.

Pick a random element from an array

Swift 4.2 and above

The new recommended approach is a built-in method on the Collection protocol: randomElement(). It returns an optional to avoid the empty case I assumed against previously.

let array = ["Frodo", "Samwise", "Merry", "Pippin"]
print(array.randomElement()!) // Using ! knowing I have array.count > 0

If you don't create the array and aren't guaranteed count > 0, you should do something like:

if let randomElement = array.randomElement() { 
print(randomElement)
}

Swift 4.1 and below

Just to answer your question, you can do this to achieve random array selection:

let array = ["Frodo", "Samwise", "Merry", "Pippin"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])

The castings are ugly, but I believe they're required unless someone else has another way.

Get random elements from array in Swift

Xcode 11 • Swift 5.1

extension Collection {
func choose(_ n: Int) -> ArraySlice<Element> { shuffled().prefix(n) }
}

Playground testing

var alphabet = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
let shuffledAlphabet = alphabet.shuffled() // "O", "X", "L", "D", "N", "K", "R", "E", "S", "Z", "I", "T", "H", "C", "U", "B", "W", "M", "Q", "Y", "V", "A", "G", "P", "F", "J"]
let letter = alphabet.randomElement() // "D"
var numbers = Array(0...9)
let shuffledNumbers = numbers.shuffled()
shuffledNumbers // [8, 9, 3, 6, 0, 1, 4, 2, 5, 7]
numbers // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
numbers.shuffle() // mutate it [6, 0, 2, 3, 9, 1, 5, 7, 4, 8]
numbers // [6, 0, 2, 3, 9, 1, 5, 7, 4, 8]
let pick3numbers = numbers.choose(3) // [8, 9, 2]

extension RangeReplaceableCollection {
/// Returns a new Collection shuffled
var shuffled: Self { .init(shuffled()) }
/// Shuffles this Collection in place
@discardableResult
mutating func shuffledInPlace() -> Self {
self = shuffled
return self
}
func choose(_ n: Int) -> SubSequence { shuffled.prefix(n) }
}

var alphabetString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let shuffledAlphabetString = alphabetString.shuffled // "DRGXNSJLFQHPUZTBKVMYAWEICO"
let character = alphabetString.randomElement() // "K"
alphabetString.shuffledInPlace() // mutate it "WYQVBLGZKPFUJTHOXERADMCINS"
alphabetString // "WYQVBLGZKPFUJTHOXERADMCINS"
let pick3Characters = alphabetString.choose(3) // "VYA"

Random number from an array without repeating the same number twice in a row?

The code below doesn't random the same number.

   var currentNo: UInt32 = 0

func randomNumber(maximum: UInt32) -> Int {

var randomNumber: UInt32

do {
randomNumber = (arc4random_uniform(maximum))
}while currentNo == randomNumber

currentNo = randomNumber

return Int(randomNumber)
}

How to generate a random number in Swift without repeating the previous random number?

Store the previous generated number in a variable and compare the generated number to the previous number. If they match generate a new random number. Repeat the generation of new numbers until they don't match.

var previousNumber: UInt32? // used in randomNumber() 

func randomNumber() -> UInt32 {
var randomNumber = arc4random_uniform(10)
while previousNumber == randomNumber {
randomNumber = arc4random_uniform(10)
}
previousNumber = randomNumber
return randomNumber
}

How to avoid generating the same random String twice in a row in Swift?

Since you only care about not repeating the value as the next value, just remember the previous value and reject the next value if it is the same as the previous value.

Here's a playground example. First, we try this the simplest way:

let pep = ["manny", "moe", "jack"]

func fetchRandomPep() -> String {
return pep.randomElement()!
}

for _ in 1...100 {
let result = fetchRandomPep()
print(result)
}

Well, you probably got many repeated results. Let's prevent that by writing our loop in a different way:

var prev = ""
for _ in 1...100 {
var result = fetchRandomPep()
while result == prev {
result = fetchRandomPep()
}
prev = result
print(result)
}

Now there are no repetitions!



Related Topics



Leave a reply



Submit