Fel*_*len 180 arrays random swift
假设我有一个数组,我想随机选择一个元素.
最简单的方法是什么?
显而易见的方式是array[random index]
.但也许有类似红宝石的东西array.sample
?或者如果没有,可以使用扩展程序创建这样的方法?
Luc*_*ugh 305
Swift 4.2及以上版本
新推荐的方法是一种内置方法:randomElement()
.它返回一个可选项以避免我之前假设的空案例.
let array = ["Frodo", "Sam", "Wise", "Gamgee"]
print(array.randomElement()!) // Using ! knowing I have array.count > 0
Run Code Online (Sandbox Code Playgroud)
如果您不创建数组并且不保证计数> 0,您应该执行以下操作:
if let randomElement = array.randomElement() {
print(randomElement)
}
Run Code Online (Sandbox Code Playgroud)
Swift 4.1及以下版本
只是回答你的问题,你可以这样做以实现随机数组选择:
let array = ["Frodo", "sam", "wise", "gamgee"]
let randomIndex = Int(arc4random_uniform(UInt32(array.count)))
print(array[randomIndex])
Run Code Online (Sandbox Code Playgroud)
铸件是丑陋的,但我相信它们是必需的,除非别人有另一种方式.
Pha*_*sky 137
关于Lucas所说的,你可以像这样创建一个Array类的扩展:
extension Array {
func randomItem() -> Element? {
if isEmpty { return nil }
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
Run Code Online (Sandbox Code Playgroud)
例如:
let myArray = [1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16]
let myItem = myArray.randomItem() // Note: myItem is an Optional<Int>
Run Code Online (Sandbox Code Playgroud)
And*_*eev 45
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)))]
}
}
Run Code Online (Sandbox Code Playgroud)
mil*_*los 21
在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
Run Code Online (Sandbox Code Playgroud)
首先,random
为UnsignedIntegerType
s 实现静态属性:
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)
}
}
Run Code Online (Sandbox Code Playgroud)
那么,对于ClosedInterval
有UnsignedIntegerType
边界的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))
}
}
Run Code Online (Sandbox Code Playgroud)
然后(稍微复杂一点),对于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)
}
}
Run Code Online (Sandbox Code Playgroud)
...其中unsignedDistanceTo
,unsignedDistanceFromMin
并plusMinIntMax
辅助方法可以实现如下:
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) }
}
}
Run Code Online (Sandbox Code Playgroud)
最后,对于所有集合,其中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]
}
}
Run Code Online (Sandbox Code Playgroud)
...可以对整数Range
s 进行一点优化:
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
}
}
Run Code Online (Sandbox Code Playgroud)
Nat*_*bot 18
你可以使用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
Run Code Online (Sandbox Code Playgroud)
小智 9
另一个Swift 3的建议
private extension Array {
var randomElement: Element {
let index = Int(arc4random_uniform(UInt32(count)))
return self[index]
}
}
Run Code Online (Sandbox Code Playgroud)