skip to Main Content

I am new to Swift and I am looking to go through an entire list of strings with no repeating elements.

var dare = ["do1", "do2", "do3", "do4", "do5"]

func dareTapped(){
    var randomNumber = Int.random(in: 0..<5)
    text.text = dare[randomNumber]  
}

This gives me random strings but they repeat a bit too often.

2

Answers


  1. You can make a copy, shuffle and get the last element like:

    var copy = dare.shuffled()
    func uniqueElement() -> String? { copy.popLast() }
    

    To repeat this process, you can do something like:

    /// Generates a random accessor for the given source.
    ///
    /// `T` should be something that can be compared to see if there is a repeating element after shuffling up.
    class UniqueAccessor<T: Equatable> {
        let source: [T]
        init(source: [T]) { self.source = source }
    
        /// Will be used for randomizing.
        private var remaining = [T]()
        /// Will be used to prevent repeat after running out of elements.
        private var lastElement: T?
    
        func uniqueElement() -> T? {
            /// Empty array does not have any random elements.
            guard !source.isEmpty else { return nil }
            /// Refill the randomizer if running out of elements.
            if remaining.isEmpty {
                remaining = source.shuffled()
                // Shift the array if the next element is same as the last.
                if lastElement == remaining.last { remaining = [remaining.last!] + remaining.dropLast() }
            }
            /// Remove the last item as the random element to prevent repeating.
            lastElement = remaining.popLast()
            return lastElement
        }
    }
    

    Usage:

    let accessor = UniqueAccessor(source: dare)
    accessor.uniqueElement()
    
    Login or Signup to reply.
  2. This is a slightly different approach.

    A second temporary array is needed.

    • On the first call the temporary array is empty, the function copies dare to tempDare and calls itself a second time.
    • On subsequent calls the function retrieves a random index of the tempDare array. Then it removes the item from the array and displays it simultaneously.

    When the array runs out of elements the cycle starts over.

    let dare = ["do1", "do2", "do3", "do4", "do5"]
    
    private var tempDare = [String]()
    
    func dareTapped(){
        if let randomIndex = tempDare.indices.randomElement() {
           text.text = tempDare.remove(at: randomIndex)
        } else {
            tempDare = dare
            dareTapped()
        }
    }
    

    PS: Joakim, I apologize for reopening the question

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search