How do I shuffle an array in Swift?

前端 未结 25 2640
长发绾君心
长发绾君心 2020-11-21 05:44

How do I randomize or shuffle the elements within an array in Swift? For example, if my array consists of 52 playing cards, I want to shuffle the array in o

25条回答
  •  谎友^
    谎友^ (楼主)
    2020-11-21 06:28

    With Swift 3, if you want to shuffle an array in place or get a new shuffled array from an array, AnyIterator can help you. The idea is to create an array of indices from your array, to shuffle those indices with an AnyIterator instance and swap(_:_:) function and to map each element of this AnyIterator instance with the array's corresponding element.


    The following Playground code shows how it works:

    import Darwin // required for arc4random_uniform
    
    let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
    var indexArray = Array(array.indices)
    var index = indexArray.endIndex
    
    let indexIterator: AnyIterator = AnyIterator {
        guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
            else { return nil }
    
        index = nextIndex
        let randomIndex = Int(arc4random_uniform(UInt32(index)))
        if randomIndex != index {
            swap(&indexArray[randomIndex], &indexArray[index])
        }
    
        return indexArray[index]
    }
    
    let newArray = indexIterator.map { array[$0] }
    print(newArray) // may print: ["Jock", "Ellie", "Sue Ellen", "JR", "Pamela", "Bobby"]
    

    You can refactor the previous code and create a shuffled() function inside an Array extension in order to get a new shuffled array from an array:

    import Darwin // required for arc4random_uniform
    
    extension Array {
    
        func shuffled() -> Array {
            var indexArray = Array(indices)        
            var index = indexArray.endIndex
    
            let indexIterator = AnyIterator {
                guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
                    else { return nil }
    
                index = nextIndex                
                let randomIndex = Int(arc4random_uniform(UInt32(index)))
                if randomIndex != index {
                    swap(&indexArray[randomIndex], &indexArray[index])
                }
    
                return indexArray[index]
            }
    
            return indexIterator.map { self[$0] }
        }
    
    }
    

    Usage:

    let array = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
    let newArray = array.shuffled()
    print(newArray) // may print: ["Bobby", "Pamela", "Jock", "Ellie", "JR", "Sue Ellen"]
    
    let emptyArray = [String]()
    let newEmptyArray = emptyArray.shuffled()
    print(newEmptyArray) // prints: []
    

    As an alternative to the previous code, you can create a shuffle() function inside an Array extension in order to shuffle an array in place:

    import Darwin // required for arc4random_uniform
    
    extension Array {
    
        mutating func shuffle() {
            var indexArray = Array(indices)
            var index = indexArray.endIndex
    
            let indexIterator = AnyIterator {
                guard let nextIndex = indexArray.index(index, offsetBy: -1, limitedBy: indexArray.startIndex)
                    else { return nil }
    
                index = nextIndex                
                let randomIndex = Int(arc4random_uniform(UInt32(index)))
                if randomIndex != index {
                    swap(&indexArray[randomIndex], &indexArray[index])
                }
    
                return indexArray[index]
            }
    
            self = indexIterator.map { self[$0] }
        }
    
    }
    

    Usage:

    var mutatingArray = ["Jock", "Ellie", "Sue Ellen", "Bobby", "JR", "Pamela"]
    mutatingArray.shuffle()
    print(mutatingArray) // may print ["Sue Ellen", "Pamela", "Jock", "Ellie", "Bobby", "JR"]
    

提交回复
热议问题