Допустим, я хочу сгенерировать случайное число от 1 до 100, но не хочу включать 42. Как мне это сделать, не повторяя случайный метод, пока не будет 42.
Как сгенерировать случайное число, не включая единицу, без использования цикла while?
Ответы (2)
Обновлено для Swift 5.1
Исключая 1 значение
var nums = [Int](1...100)
nums.remove(at: 42)
let random = Int(arc4random_uniform(UInt32(nums.count)))
print(nums[random])
Исключение нескольких значений
Это расширение Range
обеспечивает решение, когда вы хотите исключить более 1 значения.
extension ClosedRange where Element: Hashable {
func random(without excluded:[Element]) -> Element {
let valid = Set(self).subtracting(Set(excluded))
let random = Int(arc4random_uniform(UInt32(valid.count)))
return Array(valid)[random]
}
}
Пример
(1...100).random(without: [40,50,60])
Я полагаю, что вычислительная сложность этого второго решения равна O(n)
, где n — количество элементов, включенных в диапазон.
Здесь предполагается, что вызывающая сторона предоставляет не более n исключенных значений.
O(1)
времени и O(1)
места по сравнению с O(n)
временем и O(n)
пространством, необходимыми моему.
- person Luca Angeletti; 05.02.2016
В appzYourLife есть несколько отличных решений общего назначения, но я хочу решить конкретную проблему простым способом.
Оба этих подхода работают примерно одинаково: сузьте диапазон до генератора случайных чисел, чтобы удалить невозможный ответ (99 ответов вместо 100), затем сопоставьте результат, чтобы он не был недопустимым значением.
Ни один из подходов не увеличивает вероятность исхода по сравнению с другим исходом. То есть, предполагая, что ваша функция случайных чисел совершенно случайна, результат все равно будет случайным (и, например, нет двукратного шанса 43 относительно 5).
Подход 1: Дополнение.
Получите случайное число от 1 до 99. Если оно больше или равно числу, которого вы хотите избежать, добавьте к нему единицу.
func approach1()->Int {
var number = Int(arc4random_uniform(99)+1)
if number >= 42 {
number = number + 1
}
return number
}
Например, пытаясь сгенерировать случайное число от 1 до 5, отличное от 3, возьмите случайное число от 1 до 4 и добавьте единицу, если оно больше или равно 3.
- rand(1..4) дает 1, +0, = 1
- rand(1..4) дает 2, +0, = 2
- rand(1..4) дает 3, +1, = 4
- rand(1..4) дает 4, +1, = 5
Подход 2: Избегание.
Другой простой способ — получить число от 1 до 99. Если оно точно равно числу, которого вы пытаетесь избежать, вместо этого сделайте его 100.
func approach2()->Int {
var number = Int(arc4random_uniform(99)+1)
if number == 42 {
number = 100
}
return number
}
Используя этот алгоритм и снова сузив диапазон до 1-5 (избегая при этом 3), мы получаем следующие возможные результаты:
- rand(1..4) дает 1; разрешено, поэтому Результат = 1
- rand(1..4) дает 2, разрешено, поэтому Результат = 2
- rand(1..4) дает 3; не разрешено, поэтому Результат = 5
- rand(1..4) дает 4, допустимо, поэтому Result = 4