Вызов разной степени случайности arc4random в Swift?

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


person Gavin    schedule 31.08.2018    source источник


Ответы (3)


Для этого вам нужно сгенерировать два значения: ваше случайное 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 
person vacawama    schedule 31.08.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:).

person XmasRights    schedule 31.08.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()))
}
person David Berry    schedule 31.08.2018