从数组中选择一个随机元素

 手机用户2502901401 发布于 2023-01-12 09:15

假设我有一个数组,我想随机选择一个元素.

最简单的方法是什么?

显而易见的方式是array[random index].但也许有类似红宝石的东西array.sample?或者如果没有,可以使用扩展程序创建这样的方法?

6 个回答
  • 关于Lucas所说的,你可以像这样创建一个Array类的扩展:

    extension Array {
        func randomItem() -> Element? {
            if isEmpty { return nil }
            let index = Int(arc4random_uniform(UInt32(self.count)))
            return self[index]
        }
    }
    

    例如:

    let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16]
    let myItem = myArray.randomItem() // Note: myItem is an Optional<Int>
    

    2023-01-12 09:16 回答
  • Swift 4.2及以上版本

    新推荐的方法是一种内置方法:randomElement().它返回一个可选项以避免我之前假设的空案例.

    let array = ["Frodo", "Sam", "Wise", "Gamgee"]
    print(array.randomElement()!) // Using ! knowing I have array.count > 0
    

    如果您不创建数组并且不保证计数> 0,您应该执行以下操作:

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

    Swift 4.1及以下版本

    只是回答你的问题,你可以这样做以实现随机数组选择:

    let array = ["Frodo", "sam", "wise", "gamgee"]
    let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
    print(array[randomIndex])
    

    铸件是丑陋的,但我相信它们是必需的,除非别人有另一种方式.

    2023-01-12 09:17 回答
  • Swift 4版本:

    extension Collection where Index == Int {
    
        /**
         Picks a random element of the collection.
    
         - returns: A random element of the collection.
         */
        func randomElement() -> Iterator.Element? {
            return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))]
        }
    
    }
    

    2023-01-12 09:17 回答
  • Swift 2.2中,这可以推广,以便我们有:

    UInt.random
    UInt8.random
    UInt16.random
    UInt32.random
    UInt64.random
    UIntMax.random
    
    // closed intervals:
    
    (-3...3).random
    (Int.min...Int.max).random
    
    // and collections, which return optionals since they can be empty:
    
    (1..<4).sample
    [1,2,3].sample
    "abc".characters.sample
    ["a": 1, "b": 2, "c": 3].sample
    

    首先,randomUnsignedIntegerTypes 实现静态属性:

    import Darwin
    
    func sizeof <T> (_: () -> T) -> Int { // sizeof return type without calling
        return sizeof(T.self)
    }
    
    let ARC4Foot: Int = sizeof(arc4random)
    
    extension UnsignedIntegerType {
        static var max: Self { // sadly `max` is not required by the protocol
            return ~0
        }
        static var random: Self {
            let foot = sizeof(Self)
            guard foot > ARC4Foot else {
                return numericCast(arc4random() & numericCast(max))
            }
            var r = UIntMax(arc4random())
            for i in 1..<(foot / ARC4Foot) {
                r |= UIntMax(arc4random()) << UIntMax(8 * ARC4Foot * i)
            }
            return numericCast(r)
        }
    }
    

    那么,对于ClosedIntervalUnsignedIntegerType边界的s :

    extension ClosedInterval where Bound : UnsignedIntegerType {
        var random: Bound {
            guard start > 0 || end < Bound.max else { return Bound.random }
            return start + (Bound.random % (end - start + 1))
        }
    }
    

    然后(稍微复杂一点),对于ClosedInterval带有SignedIntegerType边界的s (使用下面进一步描述的辅助方法):

    extension ClosedInterval where Bound : SignedIntegerType {
        var random: Bound {
            let foot = sizeof(Bound)
            let distance = start.unsignedDistanceTo(end)
            guard foot > 4 else { // optimisation: use UInt32.random if sufficient
                let off: UInt32
                if distance < numericCast(UInt32.max) {
                    off = UInt32.random % numericCast(distance + 1)
                } else {
                    off = UInt32.random
                }
                return numericCast(start.toIntMax() + numericCast(off))
            }
            guard distance < UIntMax.max else {
                return numericCast(IntMax(bitPattern: UIntMax.random))
            }
            let off = UIntMax.random % (distance + 1)
            let x = (off + start.unsignedDistanceFromMin).plusMinIntMax
            return numericCast(x)
        }
    }
    

    ...其中unsignedDistanceTo,unsignedDistanceFromMinplusMinIntMax辅助方法可以实现如下:

    extension SignedIntegerType {
        func unsignedDistanceTo(other: Self) -> UIntMax {
            let _self = self.toIntMax()
            let other = other.toIntMax()
            let (start, end) = _self < other ? (_self, other) : (other, _self)
            if start == IntMax.min && end == IntMax.max {
                return UIntMax.max
            }
            if start < 0 && end >= 0 {
                let s = start == IntMax.min ? UIntMax(Int.max) + 1 : UIntMax(-start)
                return s + UIntMax(end)
            }
            return UIntMax(end - start)
        }
        var unsignedDistanceFromMin: UIntMax {
            return IntMax.min.unsignedDistanceTo(self.toIntMax())
        }
    }
    
    extension UIntMax {
        var plusMinIntMax: IntMax {
            if self > UIntMax(IntMax.max) { return IntMax(self - UIntMax(IntMax.max) - 1) }
            else { return IntMax.min + IntMax(self) }
        }
    }
    

    最后,对于所有集合,其中Index.Distance == Int:

    extension CollectionType where Index.Distance == Int {
        var sample: Generator.Element? {
            if isEmpty { return nil }
            let end = UInt(count) - 1
            let add = (0...end).random
            let idx = startIndex.advancedBy(Int(add))
            return self[idx]
        }
    }
    

    ...可以对整数Ranges 进行一点优化:

    extension Range where Element : SignedIntegerType {
        var sample: Element? {
            guard startIndex < endIndex else { return nil }
            let i: ClosedInterval = startIndex...endIndex.predecessor()
            return i.random
        }
    }
    
    extension Range where Element : UnsignedIntegerType {
        var sample: Element? {
            guard startIndex < endIndex else { return nil }
            let i: ClosedInterval = startIndex...endIndex.predecessor()
            return i.random
        }
    }
    

    2023-01-12 09:19 回答
  • 你可以使用Swift的内置random()函数来扩展:

    extension Array {
        func sample() -> Element {
            let randomIndex = Int(rand()) % count
            return self[randomIndex]
        }
    }
    
    let array = [1, 2, 3, 4]
    
    array.sample() // 2
    array.sample() // 2
    array.sample() // 3
    array.sample() // 3
    
    array.sample() // 1
    array.sample() // 1
    array.sample() // 3
    array.sample() // 1
    

    2023-01-12 09:20 回答
  • 另一个Swift 3的建议

    private extension Array {
        var randomElement: Element {
            let index = Int(arc4random_uniform(UInt32(count)))
            return self[index]
        }
    }
    

    2023-01-12 09:20 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有