.shuffle()和.shuffled()是Swift的一部分
原历史问题:
我如何随机或洗牌在Swift数组中的元素?例如,如果我的数组包含52张扑克牌,我想要洗牌数组以洗牌牌组。
.shuffle()和.shuffled()是Swift的一部分
原历史问题:
我如何随机或洗牌在Swift数组中的元素?例如,如果我的数组包含52张扑克牌,我想要洗牌数组以洗牌牌组。
当前回答
swift 4.2有两个方便的功能:
// shuffles the array in place
myArray.shuffle()
and
// generates a new array with shuffled elements of the old array
let newArray = myArray.shuffled()
其他回答
这是Nate为Swift 4实现的Fisher-Yates shuffle的一个版本 (Xcode 9)。
extension MutableCollection {
/// Shuffle the elements of `self` in-place.
mutating func shuffle() {
for i in indices.dropLast() {
let diff = distance(from: i, to: endIndex)
let j = index(i, offsetBy: numericCast(arc4random_uniform(numericCast(diff))))
swapAt(i, j)
}
}
}
extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffled() -> [Element] {
var list = Array(self)
list.shuffle()
return list
}
}
这些变化是:
约束indexes . iterator . element == Index现在是部分 的收集协议,并且不需要强加于 扩展了。 交换元素必须通过调用集合上的swapAt()来完成, 添加mutableccollection . swapat(_:_:)。 Element是Iterator.Element的别名。
编辑:正如在其他回答中提到的,Swift 4.2最终在标准库中添加了随机数生成,并完成了数组变换。
然而,GameplayKit中的GKRandom / GKRandomDistribution套件仍然可以与新的RandomNumberGenerator协议一起使用-如果您添加扩展到GameplayKit rng以符合新的标准库协议,您可以轻松获得:
可发送的rng(在测试需要时可以复制“随机”序列) 为了速度而牺牲健壮性的rng 产生非均匀分布的rng
...并且仍然可以使用Swift中漂亮的新“本地”随机api。
这个答案的其余部分涉及到这些rng和/或它们在旧的Swift编译器中的使用。
这里已经有一些很好的答案,以及一些很好的说明为什么如果不小心,编写自己的shuffle可能容易出错。
在iOS 9、macOS 10.11和tvOS 9(或更高版本)中,你不必自己编写。GameplayKit中有一个有效且正确的Fisher-Yates执行方法(游戏邦注:尽管它的名字叫Fisher-Yates,但它并不只是用于游戏)。
如果你只是想要一个独特的洗牌:
let shuffled = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: array)
如果您希望能够复制洗牌或一系列洗牌,请选择并播种一个特定的随机源;如。
let lcg = GKLinearCongruentialRandomSource(seed: mySeedValue)
let shuffled = lcg.arrayByShufflingObjects(in: array)
在iOS 10 / macOS 10.12 / tvOS 10中,也有一个方便的语法,可以通过NSArray的扩展进行变换。当然,当你使用Swift数组时,这有点麻烦(并且它在返回Swift时失去了它的元素类型):
let shuffled1 = (array as NSArray).shuffled(using: random) // -> [Any]
let shuffled2 = (array as NSArray).shuffled() // use default random source
但是为它创建一个保持类型的Swift包装器非常简单:
extension Array {
func shuffled(using source: GKRandomSource) -> [Element] {
return (self as NSArray).shuffled(using: source) as! [Element]
}
func shuffled() -> [Element] {
return (self as NSArray).shuffled() as! [Element]
}
}
let shuffled3 = array.shuffled(using: random)
let shuffled4 = array.shuffled()
这是一些在playground上运行的代码。你不需要在实际的Xcode项目中导入Darwin。
import darwin
var a = [1,2,3,4,5,6,7]
func shuffle<ItemType>(item1: ItemType, item2: ItemType) -> Bool {
return drand48() > 0.5
}
sort(a, shuffle)
println(a)
斯威夫特4 在for循环中洗牌数组的元素,其中i是混合比例
var cards = [Int]() //Some Array
let i = 4 // is the mixing ratio
func shuffleCards() {
for _ in 0 ..< cards.count * i {
let card = cards.remove(at: Int(arc4random_uniform(UInt32(cards.count))))
cards.insert(card, at: Int(arc4random_uniform(UInt32(cards.count))))
}
}
或者扩展为Int
func shuffleCards() {
for _ in 0 ..< cards.count * i {
let card = cards.remove(at: cards.count.arc4random)
cards.insert(card, at: cards.count.arc4random)
}
}
extension Int {
var arc4random: Int {
if self > 0 {
print("Arc for random positiv self \(Int(arc4random_uniform(UInt32(self))))")
return Int(arc4random_uniform(UInt32(self)))
} else if self < 0 {
print("Arc for random negotiv self \(-Int(arc4random_uniform(UInt32(abs(self)))))")
return -Int(arc4random_uniform(UInt32(abs(self))))
} else {
print("Arc for random equal 0")
return 0
}
}
}
工作! !生物体是要洗牌的数组。
extension Array
{
/** Randomizes the order of an array's elements. */
mutating func shuffle()
{
for _ in 0..<10
{
sort { (_,_) in arc4random() < arc4random() }
}
}
}
var organisms = [
"ant", "bacteria", "cougar",
"dog", "elephant", "firefly",
"goat", "hedgehog", "iguana"]
print("Original: \(organisms)")
organisms.shuffle()
print("Shuffled: \(organisms)")