ruby 在Swift中生成强力球选择的一行程序?

wlsrxk51  于 12个月前  发布在  Ruby
关注(0)|答案(5)|浏览(117)

随着美国本周15亿美元的大型彩票,我用Ruby写了一个函数来选择强力球。在Powerball中,从1..69范围中选择5个数字(没有重复),从1..26范围中选择1个数字。
这是我想出来的:

def pball
    Array(1..69).shuffle[0..4].sort + [rand(1..26)]
end

它的工作原理是创建一个从1到69的整数数组,对该数组进行 Shuffle ,选择前5个数字,对它们进行排序,最后添加一个从1到26的数字。
要在Swift中做到这一点需要更多的工作,因为Swift在Array上没有内置的shuffle方法。
这是我的尝试:

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...69范围内。然后,它使用map创建[(Int, Double)],这是一个包含数字和0.0 ..< 1.0范围内的随机Double的元组对数组。然后,它使用Double值对这个数组进行排序,并使用第二个map返回到[Int],然后使用切片[0...4]提取前5个数字,并使用sort()对它们进行排序。
在第二行中,它附加了一个范围为1...26的数字。我尝试在第一行添加这个,但Swift给出了错误:
表达过于复杂,无法在合理的时间内解决;考虑将表达式分解为不同的子表达式。
有人能建议如何将其转换为单行函数吗?也许有一个更好的方法来选择1...69中的5个数字。

6mzjoqzu

6mzjoqzu1#

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]
sauutmhj

sauutmhj2#

我不觉得“一行程序”的概念很有说服力。有些语言也有这种倾向;其他人则不然。我建议给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]

但是,哎呀,我忽略了你的排序。我不知道如何做到这一点,而不会得到“太复杂”的错误;为了解决这个问题,我不得不把它分成两行:

var result = Array(1...69).shuffle().shuffle().shuffle().shuffle()[0..<5].sort(<)
result.append(Int(arc4random_uniform(26)) + 1)
3wabscal

3wabscal3#

Xcode 10 · Swift 4.2
Swift现在已经将shuffled()添加到ClosedRange,将random(in:)添加到Int,现在可以在一行中轻松完成:

func pball() -> [Int] {
    return (1...69).shuffled().prefix(5).sorted() + [Int.random(in: 1...26)]
}

更多详情:

由于返回类型为pball(),因此可以在random方法调用中推断出Int。此外,.prefix(5)可以替换为[...4]。最后,return可以从单行函数中省略:

func pball() -> [Int] {
    (1...69).shuffled()[...4].sorted() + [.random(in: 1...26)]
}
6fe3ivhb

6fe3ivhb4#

不如这样吧:

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)]
mqkwyuun

mqkwyuun5#

为了好玩,Swift 3的一个非GameplayKit(长)一行程序,使用全局sequence(state:next:)函数从可变的state数组中生成随机元素,而不是对数组进行 Shuffle (尽管对值数组进行了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]

相关问题