本周美国票房收入超过15亿美元,我在Ruby中编写了一个函数来制作强力球。在Powerball中,您可以选择1..69
范围内的5个数字(没有重复项)和范围1..26
中的1个数字。
这就是我提出的:
def pball
Array(1..69).shuffle[0..4].sort + [rand(1..26)]
end
它的工作原理是创建一个从1到69的整数数组,对该数组进行混洗,选择前5个数字,对它们进行排序,最后添加1到26之间的数字。
要在Swift中执行此操作需要更多工作,因为Swift在shuffle
上没有内置的Array
方法。
这是我的尝试:
func pball() -> [Int] {
let arr = Array(1...69).map{($0, drand48())}.sort{$0.1 < $1.1}.map{$0.0}[0...4].sort()
return arr + [Int(arc4random_uniform(26) + 1)]
}
由于没有shuffle
方法,因此可以通过创建范围为[Int]
的{{1}}来实现。然后,它使用1...69
创建map
,这是一个包含数字的元组对数组,以及[(Int, Double)]
范围内的随机Double
。然后,它使用0.0 ..< 1.0
值对此数组进行排序,并使用第二个Double
返回map
,然后使用切片[Int]
提取前5个数字并{{1对它们进行排序。
在第二行中,它会在[0...4]
范围内附加一个数字。我尝试将其添加到第一行,但Swift给出了错误:
表达太复杂,无法在合理的时间内解决;考虑 将表达式分解为不同的子表达式。
有人可以建议如何将其转换为1行功能吗?也许有更好的方法可以从sort()
中选择5个数字。
答案 0 :(得分:6)
Xcode 8.3•Swift 3.1
import GameKit
var powerballNumbers: [Int] {
return (GKRandomSource.sharedRandom().arrayByShufflingObjects(in: Array(1...69)) as! [Int])[0..<5].sorted() + [Int(arc4random_uniform(26) + 1)]
}
powerballNumbers // [5, 9, 62, 65, 69, 2]
Swift 2.x
import GameKit
var powerballNumbers: [Int] {
return (GKRandomSource.sharedRandom().arrayByShufflingObjectsInArray(Array(1...69)) as! [Int])[0...4].sort() + [Int(arc4random_uniform(26).successor())]
}
powerballNumbers // [21, 37, 39, 42, 65, 23]
答案 1 :(得分:5)
我找不到&#34; one-liner&#34;概念非常引人注目。有些语言适合它;其他人不要。我建议给Swift一个shuffle
方法开始:
extension Array {
mutating func shuffle () {
for var i = self.count - 1; i != 0; i-- {
let ix1 = i
let ix2 = Int(arc4random_uniform(UInt32(i+1)))
(self[ix1], self[ix2]) = (self[ix2], self[ix1])
}
}
}
但是因为我做了这个mutating
,我们仍然需要不止一行来表达整个操作,因为我们必须对起始数组有一个var
引用:
var arr = Array(1...69)
(1...4).forEach {_ in arr.shuffle()}
let result = Array(arr[0..<5]) + [Int(arc4random_uniform(26)) + 1]
如果你真的坚持单行,并且你不计算实现shuffle
所需的代码,那么你可以通过定义shuffle
更多来做到这一点,尽管效率较低像这样:
extension Array {
func shuffle () -> [Element] {
var arr = self
for var i = arr.count - 1; i != 0; i-- {
let ix1 = i
let ix2 = Int(arc4random_uniform(UInt32(i+1)))
(arr[ix1], arr[ix2]) = (arr[ix2], arr[ix1])
}
return arr
}
}
这是你的单行:
let result = Array(1...69).shuffle().shuffle().shuffle().shuffle()[0..<5] + [Int(arc4random_uniform(26)) + 1]
但是哎呀,我省略了你的排序。我没有看到如何做到这一点,而不会太复杂&#34;错误;为了解决这个问题,我不得不把它分成两行:
var result = Array(1...69).shuffle().shuffle().shuffle().shuffle()[0..<5].sort(<)
result.append(Int(arc4random_uniform(26)) + 1)
答案 2 :(得分:2)
这个怎么样:
let winningDraw = (1...69).sort{ _ in arc4random_uniform(2) > 0}[0...4].sort() + [Int(arc4random_uniform(26)+1)]
上面的公式[编辑]不是随机的。但这个将是
(1...69).map({Int(rand()%1000*70+$0)}).sort().map({$0%70})[0...4].sort() + [Int(rand()%26+1)]
答案 3 :(得分:1)
为了它的乐趣,使用全局sequence(state:next:)
函数从Swable 3的非GameplayKit
(长)单行,从可变state
数组生成随机元素而不是改组数组(虽然改变了数值数组5次,所以这里有一些额外的复制操作......)
let powerballNumbers = Array(sequence(state: Array(1...69), next: {
(s: inout [Int]) -> Int? in s.remove(at: Int(arc4random_uniform(UInt32(s.count))))})
.prefix(5).sorted()) + [Int(arc4random_uniform(26) + 1)]
...为了便于阅读而细分。
(将来可能使用Swift版本)
如果type inference weren't broken inout
closure parameters(作为闭包的参数),我们可以将上面的内容减少为:
let powerballNumbers = Array(sequence(state: Array(1...69), next: {
$0.remove(at: Int(arc4random_uniform(UInt32($0.count)))) })
.prefix(5).sorted()) + [Int(arc4random_uniform(26) + 1)]
如果我们还允许以下扩展
extension Int {
var rand: Int { return Int(arc4random_uniform(UInt32(exactly: self) ?? 0)) }
}
然后,我们可以继续将单行减少到:
let powerballNumbers = Array(sequence(state: Array(1...69), next: { $0.remove(at: $0.count.rand) }).prefix(5).sorted()) + [26.rand + 1]
答案 4 :(得分:1)
Xcode 10•Swift 4.2
Swift现在在import CommonCrypto
上添加了shuffled()
,在ClosedRange
上添加了random(in:)
,这使得在一行中轻松实现这一点:
Int
其他修饰:
由于返回类型为func pball() -> [Int] {
return (1...69).shuffled().prefix(5).sorted() + [Int.random(in: 1...26)]
}
,因此可以在pball()
方法调用中推断出Int
。此外,random
可以替换为.prefix(5)
:
[...4]