【问题标题】:Calling different extent of randomness of arc4random in Swift?在 Swift 中调用不同程度的 arc4random 随机性?
【发布时间】:2018-08-31 13:30:09
【问题描述】:

这可能是一个相当愚蠢的问题。我想知道在 Swift 中使用 arc4random_uniform 是否可以实现不同的细微差别/随机性程度。这是一个例子:

let number = arc4random_uniform(10) + 1
print(number)

在这种情况下,将随机打印一个从 1 到 10 的数字。但是有没有办法可以将随机结果重复 2 到 3 次?结果会是这样的:

1, 1, 6, 6, 6, 3, 3, 8, 8, 9, 9, 9 ...

// 1) Randomly selected and 2) repeated 2 to 3 times randomly.

也许我可能会同时使用两个 arc4random_uniform 函数,但无法正确表达它们。如果您能给我一些建议,将不胜感激。

【问题讨论】:

    标签: swift arc4random


    【解决方案1】:

    为此,您需要生成两个值:随机的value 和repeatCount。此外,您需要记住这两个值,以便您可以重复 value。您可以使用自定义类来做到这一点:

    class RandomWithRepeats {
        var range: ClosedRange<Int>
        var repeatRange: ClosedRange<Int>
        var repeatCount = 0
        var value = 0
    
        init(range: ClosedRange<Int>, repeatRange: ClosedRange<Int>) {
            self.range = range
            self.repeatRange = repeatRange
        }
    
        // generate a random number in a range
        // Just use Int.random(in:) with Swift 4.2 and later
        func random(in range: ClosedRange<Int>) -> Int {
            return Int(arc4random_uniform(UInt32(range.upperBound - range.lowerBound + 1))) + range.lowerBound
        }
    
        func nextValue() -> Int {
            // if repeatCount is 0, its time to generate a new value and
            // a new repeatCount
            if repeatCount == 0 {
                // For Swift 4.2, just use Int.random(in:) instead
                value = self.random(in: range)
                repeatCount = self.random(in: repeatRange)
            }
    
            repeatCount -= 1
            return value
        }
    }
    

    示例:

    let rand = RandomWithRepeats(range: 1...10, repeatRange: 2...3)
    
    // generate 20 random repeated numbers    
    for _ in 1...20
    {
        print(rand.nextValue(), terminator: " ")
    }
    
    6 6 6 8 8 8 10 10 10 2 2 9 9 5 5 8 8 8 5 5 
    

    【讨论】:

      【解决方案2】:

      关于随机数生成器的细微差别:查看GKRandomSource。

      您在这里所做的并不是真正减少随机性,或者修改随机数生成器中的参数。您只是对一组随机整数应用一个操作(带有一个随机参数)。

      extension Collection {
      
          func duplicateItemsRandomly(range: CountableClosedRange<Int>) -> [Element] {
      
              return self.reduce(into: [Element](), { (acc, element) in
      
                  let distance = UInt32(range.upperBound - range.lowerBound + 1)
                  let count = Int(arc4random_uniform(distance) + UInt32(range.lowerBound))
                  let result = Array.init(repeating: element, count: count)
                  acc.append(contentsOf: result)
              })
          }
      }
      
      let sequence = [1, 6, 3, 8, 9]
      sequence.duplicateItemsRandomly(range: 2...3) 
      // [1, 1, 6, 6, 6, 3, 3, 3, 8, 8, 8, 9, 9, 9]
      

      P.S:如果您在 Swift 4.2 中编写此代码,请使用 Int.random(in:)。

      【讨论】:

        【解决方案3】:

        我建议自定义Sequence:

        class RepeatingRandomSequence : Sequence {
            let rangeLow, rangeSpan : UInt32
            let repeatLow, repeatSpan : UInt32
        
            init(range:Range<UInt32>, count:Range<UInt32>) {
                rangeLow = range.lowerBound
                rangeSpan = range.upperBound - range.lowerBound + 1
                repeatLow = count.lowerBound
                repeatSpan = count.upperBound - count.lowerBound + 1
            }
        
            func makeIterator() -> AnyIterator<UInt32> {
                var count : UInt32 = 0
                var value : UInt32 = 0
        
                return AnyIterator {
                    if(count <= 0) {
                        count = arc4random_uniform(self.repeatSpan) + self.repeatLow
                        value = arc4random_uniform(self.rangeSpan) + self.rangeLow
                    }
        
                    defer { count = count - 1 }
        
                    return value
                }
            }
        }
        
        let sequence = RepeatingRandomSequence(range: 0..<10, count: 2..<3)
        let randoms = sequence.makeIterator()
        

        请注意,迭代器randoms 现在使用randoms.next() 生成一个无限的随机数序列,因为该序列是无限的,所以很多东西并不是特别有用,例如sort、map 等。你可以但是像这样使用它:

        for value in random {
            print(value)
            if(value == 9) {  // or any other termination condition
                break
            }
        }
        

        或者更传统的,如:

        (0..<10).forEach { _ in
            print(String(describing: random.next()))
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多