假设我有一个数组,我想随机选择一个元素。
最简单的方法是什么?
明显的方法是array[random index]
。但是也许有像红宝石的东西array.sample
?或者如果不能通过扩展创建这种方法?
array[random number from 0 to length-1]
,但是我找不到如何快速生成随机int的方法,如果我没有被阻塞,我会在堆栈溢出时问它:)我不想在可能的情况下用一半的解决方案来污染问题像红宝石一样array.sample
假设我有一个数组,我想随机选择一个元素。
最简单的方法是什么?
明显的方法是array[random index]
。但是也许有像红宝石的东西array.sample
?或者如果不能通过扩展创建这种方法?
array[random number from 0 to length-1]
,但是我找不到如何快速生成随机int的方法,如果我没有被阻塞,我会在堆栈溢出时问它:)我不想在可能的情况下用一半的解决方案来污染问题像红宝石一样array.sample
Answers:
Swift 4.2及更高版本
推荐的新方法是Collection协议的内置方法:randomElement()
。它返回一个可选参数以避免我以前假设的空情况。
let array = ["Frodo", "Sam", "Wise", "Gamgee"]
print(array.randomElement()!) // Using ! knowing I have array.count > 0
如果不创建数组并且不能保证count> 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])
铸件很丑陋,但我相信除非别人没有其他方法,否则它们是必需的。
man arc4random
与stackoverflow.com/questions/10984974/...
removeRandomElement()
除了之外还实现其他功能randomElement()
。它将基于建模removeFirst()
,但会以随机索引删除对象。
0..<array.count
(由于多种原因,主要原因是它不适用于切片,并且容易出错)。您可以做let randomIndex = array.indices.randomElement()
,然后是let randomElement = array.remove(at: randomIndex)
。您甚至可以将其内联到let randomElement = array.remove(at: array.indices.randomElement())
。
根据卢卡斯的说法,您可以像这样创建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>
T
已重命名为Element
。
guard
检查以查看该数组是否为空,然后返回nil
。
arc4random
会使任何性能提升都变得微不足道。我已经更新了答案。
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)))]
}
}
startIndex != 0
在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
首先,为实现静态random
属性UnsignedIntegerType
:
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)
}
}
然后,对于ClosedInterval
s有UnsignedIntegerType
界:
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
s有SignedIntegerType
界限(使用下面进一步描述的辅助方法):
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
,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) }
}
}
最后,对于所有集合,其中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]
}
}
...可以针对整数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
}
}
您也可以使用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
以下其他答案,但有Swift 2支持。
extension Array {
func sample() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
extension Array {
func sample() -> Element {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
例如:
let arr = [2, 3, 5, 7, 9, 11, 13, 17, 19, 23, 29, 31]
let randomSample = arr.sample()
这是带有空数组检查的数组扩展,以提高安全性:
extension Array {
func sample() -> Element? {
if self.isEmpty { return nil }
let randomInt = Int(arc4random_uniform(UInt32(self.count)))
return self[randomInt]
}
}
您可以像这样简单地使用它:
let digits = Array(0...9)
digits.sample() // => 6
如果您更喜欢具有更多便捷功能的Framework,请签出HandySwift。您可以通过迦太基将其添加到项目中,然后像上面的示例一样使用它:
import HandySwift
let digits = Array(0...9)
digits.sample() // => 8
此外,它还包含一个选项,可一次获取多个随机元素:
digits.sample(size: 3) // => [8, 0, 7]
Swift 3-简单易用。
创建数组
var arrayOfColors = [UIColor.red, UIColor.yellow, UIColor.orange, UIColor.green]
创建随机颜色
let randomColor = arc4random() % UInt32(arrayOfColors.count)
将颜色设置为您的对象
your item = arrayOfColors[Int(randomColor)]
这是一个从SpriteKit
项目中SKLabelNode
随机更新a 的示例String
:
let array = ["one","two","three","four","five"]
let randomNumber = arc4random() % UInt32(array.count)
let labelNode = SKLabelNode(text: array[Int(randomNumber)])
如果您希望能够从数组中获得多个随机元素且没有重复元素,那么GameplayKit可以满足您的要求:
import GameplayKit
let array = ["one", "two", "three", "four"]
let shuffled = GKMersenneTwisterRandomSource.sharedRandom().arrayByShufflingObjects(in: array)
let firstRandom = shuffled[0]
let secondRandom = shuffled[1]
您可以选择几种随机性,请参见GKRandomSource:
的
GKARC4RandomSource
类使用类似于arc4random家族的C函数中采用的算法。(但是,此类的实例独立于对arc4random函数的调用。)本
GKLinearCongruentialRandomSource
类使用的算法的速度更快,但随机的,比GKARC4RandomSource类。(特别是,生成数字的低位比高位重复的频率更高。)当性能比可靠的不可预测性更重要时,请使用此源。本
GKMersenneTwisterRandomSource
类使用的算法的速度较慢,但更随机,比GKARC4RandomSource类。当重要的是您对随机数的使用不显示重复的模式并且对性能的关注较少时,请使用此来源。
我发现使用GameKit的GKRandomSource.sharedRandom()最适合我。
import GameKit
let array = ["random1", "random2", "random3"]
func getRandomIndex() -> Int {
let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(array.count)
return randomNumber
或者您可以按所选的随机索引返回对象。确保该函数先返回一个String,然后返回该数组的索引。
return array[randomNumber]
简明扼要。
现在有一个内置方法Collection
:
let foods = ["🍕", "🍔", "🍣", "🍝"]
let myDinner = foods.randomElement()
如果n
要从集合中提取最多随机元素,则可以添加如下扩展名:
extension Collection {
func randomElements(_ count: Int) -> [Element] {
var shuffledIterator = shuffled().makeIterator()
return (0..<count).compactMap { _ in shuffledIterator.next() }
}
}
如果希望它们唯一,则可以使用Set
,但集合的元素必须符合Hashable
协议:
extension Collection where Element: Hashable {
func randomUniqueElements(_ count: Int) -> [Element] {
var shuffledIterator = Set(shuffled()).makeIterator()
return (0..<count).compactMap { _ in shuffledIterator.next() }
}
}
最新的swift3代码尝试正常运行
let imagesArray = ["image1.png","image2.png","image3.png","image4.png"]
var randomNum: UInt32 = 0
randomNum = arc4random_uniform(UInt32(imagesArray.count))
wheelBackgroundImageView.image = UIImage(named: imagesArray[Int(randomNum)])
我想出了一种非常不同的方式来使用Swift 4.2中引入的新功能。
// 👇🏼 - 1
public func shufflePrintArray(ArrayOfStrings: [String]) -> String {
// - 2
let strings = ArrayOfStrings
//- 3
var stringans = strings.shuffled()
// - 4
var countS = Int.random(in: 0..<strings.count)
// - 5
return stringans[countS]
}
我们声明了一个带有参数的函数,该参数带有一个字符串数组并返回一个字符串。
然后我们将 ArrayOfStrings放在一个变量中。
它基本上是对字符串数组进行混洗,然后从总数的总数中随机选择一个数字,然后返回经过改组的数组的随机索引。