在Swift中生成强力球选择的单线程?

时间:2016-01-16 01:19:01

标签: ruby swift

本周美国票房收入超过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个数字。

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]