Вызывая разную степень случайности arc4random в Swift? - PullRequest
0 голосов
/ 31 августа 2018

Это может быть довольно глупый вопрос. Я хотел бы знать, были бы возможны различные нюансы / степень случайности, используя arc4random_uniform в Swift. Вот пример:

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 вместе, но не могу выразить их должным образом. Буду очень признателен, если вы могли бы дать мне несколько предложений. <3 </p>

Ответы [ 3 ]

0 голосов
/ 31 августа 2018

Для этого вам нужно сгенерировать два значения: ваше случайное значение 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 
0 голосов
/ 31 августа 2018

Я бы предложил пользовательский 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()))
}
0 голосов
/ 31 августа 2018

Что касается нюансов генераторов случайных чисел: взгляните на 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:).

...