Como se gera um número aleatório no idioma Swift da Apple?

443

Sei que o livro Swift forneceu uma implementação de um gerador de números aleatórios. A melhor prática é copiar e colar essa implementação no próprio programa? Ou existe uma biblioteca que faz isso que podemos usar agora?

door_number_three
fonte

Respostas:

466

Swift 4.2+

O Swift 4.2 fornecido com o Xcode 10 apresenta novas funções aleatórias fáceis de usar para muitos tipos de dados. Você pode chamar o random()método em tipos numéricos.

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
Catfish_Man
fonte
7
Eu não tinha para importar explicitamente Darwin
finneycanhelp
3
No meu arquivo do Playground, eu precisava importar o Darwin porque não estava importando mais nada.
DonnaLea
SoliQuiD: exceto omita o sublinhado extra após arc4, ou seja, arc4random_uniform (5).
Ali Beadle
3
Aviso : RC4 ou arc4 demonstrou ser distinguível dos valores aleatórios puros . Portanto, embora o arc4 (uma cifra de fluxo) pareça criptograficamente seguro, na verdade não é.
Maarten Bodewes
2
@MaartenBodewes: não é mais diretamente relevante para esta resposta, mas o arc4random na verdade não usa a cifra RC4, apesar do nome, no macOS ou nos BSDs. Ele usa um CSPRNG fornecido pelo sistema no macOS e ChaCha20 na maioria dos BSDs. O RNG padrão do Swift (conforme usado nesta resposta) o chama como um detalhe de implementação no macOS, mas usa um gerador subjacente apropriado em cada plataforma suportada.
Stephen Canon
496

Use arc4random_uniform(n)para um número inteiro aleatório entre 0 e n-1.

let diceRoll = Int(arc4random_uniform(6) + 1)

Transmitir o resultado para Int para que você não precise digitar explicitamente seus vars como UInt32(o que parece não-Swifty).

John Pavley
fonte
7
Muito simples. Eu gosto disso. Voto a favor! Mas um dado real não tem 0. No seu código, diceRollpoderia ser 0. Basta dizer ...
MK Safi
61
Sim, você realmente quer Int(arc4random_uniform(6)+1).
Michael Dorst
5
probabilidade = Int (arc4random_uniform (UInt32 (total))) - i também teve que fundido em UInt32
bshirley
4
Vamos randomElementInArray = Int (arc4random_uniform (array.count))
cmario
Não se esqueça de converter o parâmetro n, inserido em arc3random_uniform(n)a UInt32(n)se você estiver usando um valor que ainda não é desse tipo.
Dave Fontenot
117

Edit: Atualizado para Swift 3.0

arc4randomfunciona bem no Swift, mas as funções básicas são limitadas a tipos inteiros de 32 bits ( Inté de 64 bits no iPhone 5S e em Macs modernos). Aqui está uma função genérica para um número aleatório de um tipo expressável por um literal inteiro:

public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, MemoryLayout<T>.size)
    return r
}

Podemos usar essa nova função genérica para estender UInt64, adicionando argumentos de fronteira e atenuando o viés do módulo. (Isso é retirado diretamente do arc4random.c )

public extension UInt64 {
    public static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 {
        var m: UInt64
        let u = upper - lower
        var r = arc4random(UInt64.self)

        if u > UInt64(Int64.max) {
            m = 1 + ~u
        } else {
            m = ((max - (u * 2)) + 1) % u
        }

        while r < m {
            r = arc4random(UInt64.self)
        }

        return (r % u) + lower
    }
}

Com isso, podemos estender Int64os mesmos argumentos, lidando com o estouro:

public extension Int64 {
    public static func random(lower: Int64 = min, upper: Int64 = max) -> Int64 {
        let (s, overflow) = Int64.subtractWithOverflow(upper, lower)
        let u = overflow ? UInt64.max - UInt64(~s) : UInt64(s)
        let r = UInt64.random(upper: u)

        if r > UInt64(Int64.max)  {
            return Int64(r - (UInt64(~lower) + 1))
        } else {
            return Int64(r) + lower
        }
    }
}

Para completar a família ...

private let _wordSize = __WORDSIZE

public extension UInt32 {
    public static func random(lower: UInt32 = min, upper: UInt32 = max) -> UInt32 {
        return arc4random_uniform(upper - lower) + lower
    }
}

public extension Int32 {
    public static func random(lower: Int32 = min, upper: Int32 = max) -> Int32 {
        let r = arc4random_uniform(UInt32(Int64(upper) - Int64(lower)))
        return Int32(Int64(r) + Int64(lower))
    }
}

public extension UInt {
    public static func random(lower: UInt = min, upper: UInt = max) -> UInt {
        switch (_wordSize) {
            case 32: return UInt(UInt32.random(UInt32(lower), upper: UInt32(upper)))
            case 64: return UInt(UInt64.random(UInt64(lower), upper: UInt64(upper)))
            default: return lower
        }
    }
}

public extension Int {
    public static func random(lower: Int = min, upper: Int = max) -> Int {
        switch (_wordSize) {
            case 32: return Int(Int32.random(Int32(lower), upper: Int32(upper)))
            case 64: return Int(Int64.random(Int64(lower), upper: Int64(upper)))
            default: return lower
        }
    }
}

Depois de tudo isso, podemos finalmente fazer algo assim:

let diceRoll = UInt64.random(lower: 1, upper: 7)
jstn
fonte
Ele não compilar: var r = arc4random(UInt64). Por favor, informe o que você quis dizer aqui?
Ossir
@Ossir compila bem para mim ... significa chamar a função arc4random(definida no primeiro bloco de código) com o argumento UInt64que é a Type.
jstn
Arc4random_buf (e, portanto, todas as extensões de 64 bits) sofrem com a tendência do módulo?
Matthew Seaman
A polarização do módulo só entra em jogo quando você adiciona um limite superior, portanto não se aplica a arc4random_buf. O objetivo dessas extensões é fazer exatamente o que arc4random_uniformfaz (atenuar a polarização do módulo), exceto para os tipos de 64 bits.
jstn
ao usar as funções de flutuação, como posso incluir o valor superior no intervalo de possibilidades? Digamos que eu faça 0,0 como o mais baixo e 1,0 como o mais alto. Com essa lógica, me dará 0,0 a 0,99999999. Mas, em vez disso, gostaria de incluir o 1.0 como uma possibilidade. Como posso conseguir isso?
MobileMon
80

Editar para o Swift 4.2

A partir do Swift 4.2, em vez de usar a função C importada arc4random_uniform (), agora você pode usar as funções nativas do Swift.

// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)

Você também pode usar random(in:)para obter valores aleatórios para outros valores primitivos; como Int, Double, Float e até Bool.

Versões Swift <4.2

Este método irá gerar um Intvalor aleatório entre o mínimo e o máximo indicados

func randomInt(min: Int, max: Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
Groot
fonte
61

Eu usei este código:

var k: Int = random() % 10;
fockus
fonte
20
você deve chamar srandom (UInt32 (horário (zero))) primeiro, caso contrário, sempre retornará a mesma sequência numérica
Hola Soy Edu Feliz Navidad
3
Eu li o documento da apple em random () duas vezes, mas não consegui entender seu uso ... Eu gostaria que eles simplesmente incluíssem um exemplo de código simples como este acima. "A função random () usa um gerador de números aleatórios não lineares, com feedback aditivo, empregando uma tabela padrão de inteiros longos de tamanho 31. Ela retorna números pseudo-aleatórios sucessivos no intervalo de 0 a (2 31) -1. O período desse gerador de números aleatórios é muito grande, aproximadamente 16 * ((2 31) -1). " ... Muito obrigado apple ... Certificarei de referenciar isso na minha próxima tese.
Nocarrier 21/05
1
random () às vezes leva a uma falha repentina nos iPads. Se isso acontecer, use o arc4random_uniform (6) acima. Se você usar random (), poderá criar mais valores aleatórios anexando srandomdev ().
21416 JackPearse
1
Eu recebi a mensagem de erro do compilador:random is unavailable in Swift: Use arc4random instead.
Mike Keskinov
1
Esta solução possui viés de módulo: zuttobenkyou.wordpress.com/2012/10/18/…
rgov
33

No iOS 9, você pode usar as novas classes GameplayKit para gerar números aleatórios de várias maneiras.

Você tem quatro tipos de fonte para escolher: uma fonte aleatória geral (sem nome, até o sistema escolher o que faz), congruencial linear, ARC4 e Mersenne Twister. Isso pode gerar entradas, flutuadores e bools aleatórios.

No nível mais simples, você pode gerar um número aleatório a partir da fonte aleatória interna do sistema, como esta:

GKRandomSource.sharedRandom().nextInt()

Isso gera um número entre -2.147.483.648 e 2.147.483.647. Se você deseja um número entre 0 e um limite superior (exclusivo), use este:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

O GameplayKit possui alguns construtores de conveniência incorporados para trabalhar com dados. Por exemplo, você pode rolar um dado de seis lados assim:

let d6 = GKRandomDistribution.d6()
d6.nextInt()

Além disso, você pode moldar a distribuição aleatória usando coisas como GKShuffledDistribution. Isso leva um pouco mais de explicação, mas se você estiver interessado, pode ler meu tutorial sobre os números aleatórios do GameplayKit .

TwoStraws
fonte
1
Obrigado por esta dica, é uma das melhores respostas. Para usar essas funções, é necessário adicionar import GameplayKit. Swift 3 alterou a sintaxe paraGKRandomSource.sharedRandom().nextInt(upperBound: 6)
petrsyn
7
Quão pesado é este kit para importar? Eu não quero inchar meu código.
μολὼν.λαβέ
25

Você pode fazer da mesma maneira que faria em C:

let randomNumber = arc4random()

randomNumberé inferido como sendo do tipo UInt32(um número inteiro não assinado de 32 bits)

Dave DeLong
fonte
12
Adenda: rand, arc4random, drand48e amigos estão todos no Darwinmódulo. Ele já foi importado para você se você estiver criando um aplicativo Cocoa, UIKit ou Foundation, mas será necessário import Darwinem playgrounds.
rickster
5
E não tente converter o resultado de arc4random () para um Int - isso funcionará bem em uma plataforma de 64 bits, mas em uma plataforma de 32 bits, as Ints são assinadas em 32 bits, para que você obtenha resultados negativos inesperados números. Isso já provocou algumas pessoas, então eu pensei em mencionar aqui.
Matt Gibson
23

Usar arc4random_uniform()

Uso:

arc4random_uniform(someNumber: UInt32) -> UInt32

Isso fornece números inteiros aleatórios no intervalo 0de someNumber - 1.

O valor máximo para UInt32é 4.294.967.295 (ou seja, 2^32 - 1).

Exemplos:

  • Coin flip

    let flip = arc4random_uniform(2) // 0 or 1
  • Rolar os dados

    let roll = arc4random_uniform(6) + 1 // 1...6
  • Dia aleatório em outubro

    let day = arc4random_uniform(31) + 1 // 1...31
  • Ano aleatório nos anos 90

    let year = 1990 + arc4random_uniform(10)

Forma geral:

let number = min + arc4random_uniform(max - min + 1)

onde number, maxe minestão UInt32.

A respeito...

arc4random ()

Você também pode obter um número aleatório usando arc4random(), que produz UInt32entre 0 e 2 ^ 32-1. Assim, para obter um número aleatório entre 0e x-1, você pode dividi-lo xe pegar o restante. Ou, em outras palavras, use o Operador restante (%) :

let number = arc4random() % 5 // 0...4

No entanto, isso produz um leve viés de módulo (veja também aqui e aqui ), e é por isso que arc4random_uniform()é recomendado.

Convertendo de e para Int

Normalmente, seria bom fazer algo assim para converter entre Inte UInt32:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))

O problema, porém, é que Inttem um intervalo de -2,147,483,648...2,147,483,647sistemas de 32 bits e um de -9,223,372,036,854,775,808...9,223,372,036,854,775,807sistemas de 64 bits. Compare isso com o UInt32intervalo de 0...4,294,967,295. O Ude UInt32significa não assinado .

Considere os seguintes erros:

UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error

Portanto, você só precisa ter certeza de que seus parâmetros de entrada estão dentro do UInt32intervalo e também não precisa de uma saída que esteja fora desse intervalo.

Suragch
fonte
19

Exemplo para número aleatório entre 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Código muito fácil - simples e curto.

RS
fonte
16

Consegui usar apenas rand()para obter um CInt aleatório. Você pode torná-lo um Int usando algo como isto:

let myVar: Int = Int(rand())

Você pode usar sua função aleatória C favorita e apenas converter em valor para Int, se necessário.

Connor
fonte
Sim, a conversão de tipos pode ser um negócio complicado, caso contrário, deixar o construtor Int lidar com isso é um verdadeiro alívio para a dor.
precisa saber é o seguinte
4
Observe que se você não estiver chamando srand (...) (chame apenas uma vez) antes de usar rand (), a sequência de números sempre será exatamente a mesma entre cada execução do seu programa. Se você não quiser isso, use arc4random ()
SomeGuy
2
Você também pode usar random(), que retorna um Inte não UInt32- e, como o @SomeGuy mencionado, simplesmente chame srandom(arc4random())uma vez em qualquer lugar antes de usá-lo para garantir que ele tenha uma semente aleatória diferente para cada execução do seu programa.
brittlewis12
1
Alguém pode comentar sobre rand () vs arc4random_uniform ()?
Ruben Martinez Jr.
16

A resposta do @ jstn é boa, mas um pouco detalhada. O Swift é conhecido como uma linguagem orientada a protocolo, para que possamos obter o mesmo resultado sem precisar implementar o código padrão para todas as classes da família inteira, adicionando uma implementação padrão para a extensão do protocolo.

public extension ExpressibleByIntegerLiteral {
    public static func arc4random() -> Self {
        var r: Self = 0
        arc4random_buf(&r, MemoryLayout<Self>.size)
        return r
    }
}

Agora podemos fazer:

let i = Int.arc4random()
let j = UInt32.arc4random()

e todas as outras classes inteiras estão ok.

Ryne Wang
fonte
11

No Swift 4.2, você pode gerar números aleatórios chamando o random()método para qualquer tipo numérico desejado, fornecendo o intervalo com o qual deseja trabalhar. Por exemplo, isso gera um número aleatório no intervalo de 1 a 9, inclusive nos dois lados

let randInt = Int.random(in: 1..<10)

Também com outros tipos

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
Sh_Khan
fonte
9

Aqui está uma biblioteca que faz o trabalho bem https://github.com/thellimist/SwiftRandom

public extension Int {
    /// SwiftRandom extension
    public static func random(lower: Int = 0, _ upper: Int = 100) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }
}

public extension Double {
    /// SwiftRandom extension
    public static func random(lower: Double = 0, _ upper: Double = 100) -> Double {
        return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension Float {
    /// SwiftRandom extension
    public static func random(lower: Float = 0, _ upper: Float = 100) -> Float {
        return (Float(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
    }
}

public extension CGFloat {
    /// SwiftRandom extension
    public static func random(lower: CGFloat = 0, _ upper: CGFloat = 1) -> CGFloat {
        return CGFloat(Float(arc4random()) / Float(UINT32_MAX)) * (upper - lower) + lower
    }
}
demiculus
fonte
8
 let MAX : UInt32 = 9
 let MIN : UInt32 = 1

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}
Rajesh Sharma
fonte
6

Gostaria de acrescentar às respostas existentes que o exemplo de gerador de números aleatórios no livro Swift é um gerador de congruência linear (LCG), é severamente limitado e não deve ser, exceto pelos exemplos triviais, em que a qualidade da aleatoriedade não importa mesmo. E um LCG nunca deve ser usado para fins criptográficos .

arc4random()é muito melhor e pode ser usado para a maioria dos propósitos, mas novamente não deve ser usado para fins de criptografia.

Se você deseja que algo que seja garantido criptograficamente seja seguro, use SecCopyRandomBytes(). Observe que, se você criar um gerador de números aleatórios em alguma coisa, outra pessoa poderá acabar (utilizando incorretamente) para fins criptográficos (como senha, chave ou geração de sal), então você deve considerar o uso de SecCopyRandomBytes()qualquer maneira, mesmo que sua necessidade não seja ' isso exige bastante.

Jeffrey Goldberg
fonte
6

Desde o Swift 4.2

Há um novo conjunto de APIs:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • Todos os tipos numéricos agora têm o random(in:)método necessário range.

  • Retorna um número uniformemente distribuído nesse intervalo.


TL; DR

Bem, o que há de errado com o "bom" jeito antigo?

  1. Você precisa usar APIs C importadas (elas são diferentes entre plataformas) .

  2. E além disso...

E se eu lhe dissesse que o aleatório não é tão aleatório?

Se você usar arc4random() (para calcular o restante) como arc4random() % aNumber, o resultado não será distribuído uniformemente entre 0e aNumber. Há um problema chamado viés do módulo .

Viés do módulo

Normalmente, a função gera um número aleatório entre 0e MAX (depende do tipo etc.) . Para dar um exemplo rápido e fácil, digamos que o número máximo seja 7e você se preocupa com um número aleatório no intervalo 0 ..< 2 (ou no intervalo [0, 3), se preferir) .

As probabilidades para números individuais são:

  • 0: 3/8 = 37,5%
  • 1: 3/8 = 37,5%
  • 2: 2/8 = 25%

Em outras palavras, é mais provável que você termine com 0 ou 1 que 2 . Obviamente, tenha em mente que isso é extremamente simplificado e o número MAX é muito maior, tornando-o mais "justo".

Esse problema foi solucionado pelo SE-0202 - Unificação aleatória no Swift 4.2

Jakub Truhlář
fonte
5

Sem arc4Random_uniform () em algumas versões do Xcode (na 7.1, ele é executado, mas não é preenchido automaticamente). Você pode fazer isso.

Para gerar um número aleatório de 0 a 5. Primeiro

import GameplayKit

Então

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
brokenrhino
fonte
5
var randomNumber = Int(arc4random_uniform(UInt32(5)))

Aqui 5 garantirá que o número aleatório seja gerado de zero a quatro. Você pode definir o valor de acordo.

Taran Goel
fonte
1
Se você passar 5, retornará 5 resultados possíveis de zero a quatro. 0 ... 4
Leo Dabus
3

Swift 4.2

Adeus para importar a Foundation C lib arc4random_uniform()

// 1  
let digit = Int.random(in: 0..<10)

// 2
if let anotherDigit = (0..<10).randomElement() {
  print(anotherDigit)
} else {
  print("Empty range.")
}

// 3
let double = Double.random(in: 0..<1)
let float = Float.random(in: 0..<1)
let cgFloat = CGFloat.random(in: 0..<1)
let bool = Bool.random()
  1. Você usa aleatório (em :) para gerar dígitos aleatórios a partir de intervalos.
  2. randomElement () retorna nil se o intervalo estiver vazio, então você desembrulha o Int retornado? com se deixar.
  3. Você usa random (in :) para gerar um Double, Float ou CGFloat aleatório e random () para retornar um Bool aleatório.

More @ oficial

iSrinivasan27
fonte
2

O código a seguir produzirá um número aleatório seguro entre 0 e 255:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

Você chama assim:

print(UInt8.random)

Para números maiores, fica mais complicado.
Este é o melhor que eu poderia ter:

extension UInt16 {
  public static var random: UInt16 {
    let count = Int(UInt8.random % 2) + 1
    var numbers = [UInt8](repeating: 0, count: 2)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt16($1) }
  }
}

extension UInt32 {
  public static var random: UInt32 {
    let count = Int(UInt8.random % 4) + 1
    var numbers = [UInt8](repeating: 0, count: 4)
    _ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
    return numbers.reversed().reduce(0) { $0 << 8 + UInt32($1) }
  }
}

Esses métodos usam um número aleatório extra para determinar quantos UInt8s serão usados ​​para criar o número aleatório. A última linha converte o [UInt8]para UInt16ou UInt32.

Não sei se os dois últimos ainda contam como verdadeiramente aleatórios, mas você pode ajustá-lo ao seu gosto :)

Zyphrax
fonte
Você espertamente evitou o viés introduzido pelo módulo, for1 para isso. Você pode avisar os leitores por que fez isso.
JWW
Isso é interessante, eu realmente não considerava que o viés do módulo estivesse em jogo aqui. Talvez as chances de obter um número pequeno não sejam as mesmas de um número grande.
Zyphrax
2

Swift 4.2

O Swift 4.2 incluiu uma API de número aleatório nativa e bastante completa na biblioteca padrão. ( Proposta Swift Evolution SE-0202 )

let intBetween0to9 = Int.random(in: 0...9) 
let doubleBetween0to1 = Double.random(in: 0...1)

Todos os tipos de números têm o aleatório estático (em :), que pega o intervalo e retorna o número aleatório no determinado intervalo

Suhit Patil
fonte
1

Swift 4.2, Xcode 10.1 .

Para iOS, macOS e tvOS, você pode usar fonte aleatória em todo o sistema na estrutura do Xcode GameKit. Aqui você pode encontrar GKRandomSourceclasse com seu sharedRandom()método de classe:

import GameKit

let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

func randomGenerator() -> Int {
    let random = GKRandomSource.sharedRandom().nextInt(upperBound: number.count)
    return number[random]
}
randomGenerator()

Ou apenas use um randomElement()método que retorne um elemento aleatório da coleção:

let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

let randomNumber = number.randomElement()!
print(randomNumber)
Andy
fonte
0

Você pode usar GeneratorOfassim:

var fibs = ArraySlice([1, 1])
var fibGenerator = GeneratorOf{
    _ -> Int? in
    fibs.append(fibs.reduce(0, combine:+))
    return fibs.removeAtIndex(0)
}

println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
Durul Dalkanat
fonte
3
Como Fibonacci é aleatório?
Nikolai Ruhe
Oi Nikolai, Este bloco de código é a versão antiga Swift 1.2. Se você tentar o novo Swift 2.0. Não seria trabalho.
você precisa saber é o seguinte
2
Eu entendo, mas ainda parece um gerador de fibonacci para mim, não números aleatórios, como solicitado na pergunta.
Nikolai Ruhe
0

Eu uso esse código para gerar um número aleatório:

//
//  FactModel.swift
//  Collection
//
//  Created by Ahmadreza Shamimi on 6/11/16.
//  Copyright © 2016 Ahmadreza Shamimi. All rights reserved.
//

import GameKit

struct FactModel {

    let fun  = ["I love swift","My name is Ahmadreza","I love coding" ,"I love PHP","My name is ALireza","I love Coding too"]


    func getRandomNumber() -> String {

        let randomNumber  = GKRandomSource.sharedRandom().nextIntWithUpperBound(fun.count)

        return fun[randomNumber]
    }
}
Ahmadreza Shamimi
fonte
2
Bem-vindo ao SO. As respostas apenas ao código são desencorajadas - edite sua resposta para explicar por que esse código responde à pergunta e como ele funciona. Consulte stackoverflow.com/help/how-to-answer para obter mais informações.
Tim Malone
2
Forneça algum contexto em torno de sua resposta e seja bem-vindo ao stackoverflow. :)
Jonathan Eustace
0

Detalhes

xCode 9.1, Swift 4

Solução orientada a matemática (1)

import Foundation

class Random {

    subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
        get {
            return rand(min-1, max+1)
        }
    }
}

let rand = Random()

func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
    let _min = min + 1
    let difference = max - _min
    return T(arc4random_uniform(UInt32(difference))) + _min
}

Uso da solução (1)

let x = rand(-5, 5)       // x = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
let x = rand[0, 10]       // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Solução orientada a programadores (2)

Não se esqueça de adicionar o código da solução orientada a matemática (1) aqui

import Foundation

extension CountableRange where Bound : BinaryInteger {

    var random: Bound {
        return rand(lowerBound-1, upperBound)
    }
}

extension CountableClosedRange where Bound : BinaryInteger {

    var random: Bound {
        return rand[lowerBound, upperBound]
    }
}

Uso da solução (2)

let x = (-8..<2).random           // x = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1]
let x = (0..<10).random           // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let x = (-10 ... -2).random       // x = [-10, -9, -8, -7, -6, -5, -4, -3, -2]

Amostra Completa

Não se esqueça de adicionar os códigos de solução (1) e solução (2) aqui

private func generateRandNums(closure:()->(Int)) {

    var allNums = Set<Int>()
    for _ in 0..<100 {
        allNums.insert(closure())
    }
    print(allNums.sorted{ $0 < $1 })
}

generateRandNums {
    (-8..<2).random
}

generateRandNums {
    (0..<10).random
}

generateRandNums {
    (-10 ... -2).random
}

generateRandNums {
    rand(-5, 5)
}
generateRandNums {
    rand[0, 10]
}

Resultado da amostra

insira a descrição da imagem aqui

Vasily Bodnarchuk
fonte
2
Esta resposta está fora do tópico. A questão era como gerar um número aleatório. Não é como criar uma biblioteca de números aleatórios. Sheesh.
Andrew Paul Simmons