Como posso obter um número aleatório no Kotlin?

151

Um método genérico que pode retornar um número inteiro aleatório entre 2 parâmetros, como o ruby ​​faz com rand(0..n).

Alguma sugestão?

Yago Azedias
fonte

Respostas:

373

Minha sugestão seria uma função de extensão no IntRange para criar randoms como este:(0..10).random()

TL; DR Kotlin> = 1.3, um aleatório para todas as plataformas

A partir da versão 1.3, o Kotlin vem com seu próprio gerador aleatório multiplataforma. É descrito neste KEEP . A extensão descrita abaixo agora faz parte da biblioteca padrão do Kotlin , basta usá-la assim:

val rnds = (0..10).random()

Kotlin <1.3

Antes da versão 1.3, na JVM, usamos Randomou mesmo ThreadLocalRandomno JDK> 1.6.

fun IntRange.random() = 
       Random().nextInt((endInclusive + 1) - start) + start

Usado assim:

// will return an `Int` between 0 and 10 (incl.)
(0..10).random()

Se você deseja que a função retorne apenas 1, 2, ..., 9( 10não incluída), use um intervalo construído com until:

(0 until 10).random()

Se você estiver trabalhando com JDK> 1.6, use em ThreadLocalRandom.current()vez de Random().

KotlinJs e outras variações

Para kotlinjs e outros casos de uso que não permitem o uso java.util.Random, consulte esta alternativa .

Além disso, veja esta resposta para obter variações de minha sugestão. Também inclui uma função de extensão para Chars aleatórios .

s1m0nw1
fonte
Suponho que isso também usa Java java.util.Random?
Simon Forsberg 21/03
@SimonForsberg De fato. Eu adicionei outra resposta que não faz uso dela: stackoverflow.com/a/49507413/8073652
s1m0nw1
Há também uma proposta aqui para adicionar um seguro Pseudo-Random Number Generator Cryptographically (CSPRNG) aqui: github.com/Kotlin/KEEP/issues/184
Jonathan Leitschuh
41

Gere um número inteiro aleatório entre from(inclusive) e to(exclusivo)

import java.util.Random

val random = Random()

fun rand(from: Int, to: Int) : Int {
    return random.nextInt(to - from) + from
}
Magnus
fonte
1
Se você deseja obter alguns Ints aleatórios à distância , use Random # int (tamanho, de, até) em java-8 .
Holi-java
3
Esta solução não funciona em Javascript / Kotlin nativo. Talvez seja legal criar um método mais genérico para fazer isso. :)
Valentin Michalak
@ValentinMichalak você pode tentar este: stackoverflow.com/a/49507413/8073652
s1m0nw1
31

No kotlin 1.2, você poderia escrever:

(1..3).shuffled().last()

Esteja ciente de que é grande O (n), mas para uma pequena lista (especialmente de valores únicos) está tudo bem: D

mutexkid
fonte
este é útil para Kotlin-native
user3471194
11

Você pode criar uma função de extensão semelhante a java.util.Random.nextInt(int)uma que aceita um em IntRangevez de um Intpara seu limite:

fun Random.nextInt(range: IntRange): Int {
    return range.start + nextInt(range.last - range.start)
}

Agora você pode usar isso com qualquer Randominstância:

val random = Random()
println(random.nextInt(5..9)) // prints 5, 6, 7, or 8

Se você não deseja gerenciar sua própria Randominstância, pode definir um método de conveniência usando, por exemplo ThreadLocalRandom.current():

fun rand(range: IntRange): Int {
    return ThreadLocalRandom.current().nextInt(range)
}

Agora você pode obter um número inteiro aleatório como faria no Ruby sem precisar primeiro declarar uma Randominstância:

rand(5..9) // returns 5, 6, 7, or 8
mfulton26
fonte
10

Possível variação da minha outra resposta para caracteres aleatórios

Para obter Chars aleatórios , você pode definir uma função de extensão como esta

fun ClosedRange<Char>.random(): Char = 
       (Random().nextInt(endInclusive.toInt() + 1 - start.toInt()) + start.toInt()).toChar()

// will return a `Char` between A and Z (incl.)
('A'..'Z').random()

Se você estiver trabalhando com JDK> 1.6, use em ThreadLocalRandom.current() vez de Random().

Para kotlinjs e outros casos de uso que não permitem o uso java.util.Random, esta resposta ajudará.

Kotlin> = 1.3 suporte multiplataforma para Random

A partir da versão 1.3, o Kotlin vem com seu próprio gerador aleatório multiplataforma. É descrito neste KEEP . Agora você pode usar diretamente a extensão como parte da biblioteca padrão do Kotlin sem defini-la:

('a'..'b').random()
s1m0nw1
fonte
7

Com base na resposta excelente do @ s1m0nw1, fiz as seguintes alterações.

  1. (0..n) implica inclusão no Kotlin
  2. (0 até n) implica exclusivo no Kotlin
  3. Use um objeto singleton para a instância Random (opcional)

Código:

private object RandomRangeSingleton : Random()

fun ClosedRange<Int>.random() = RandomRangeSingleton.nextInt((endInclusive + 1) - start) + start

Caso de teste:

fun testRandom() {
        Assert.assertTrue(
                (0..1000).all {
                    (0..5).contains((0..5).random())
                }
        )
        Assert.assertTrue(
                (0..1000).all {
                    (0..4).contains((0 until 5).random())
                }
        )
        Assert.assertFalse(
                (0..1000).all {
                    (0..4).contains((0..5).random())
                }
        )
    }
Steven Spungin
fonte
5

Exemplos aleatórios no intervalo [1, 10]

val random1 = (0..10).shuffled().last()

ou utilizando Java Random

val random2 = Random().nextInt(10) + 1
Andrey
fonte
1
Sua primeira resposta que eu mais gosto. É um one-liner perfeita que não requre para escrever quaisquer funções de extensão
Alex Semeniuk
4

Kotlin> = 1.3, suporte multiplataforma para Random

A partir da versão 1.3, a biblioteca padrão forneceu suporte multiplataforma para randoms, veja esta resposta.

Kotlin <1.3 em JavaScript

Se você estiver trabalhando com o Kotlin JavaScript e não tiver acesso java.util.Random, o seguinte funcionará:

fun IntRange.random() = (Math.random() * ((endInclusive + 1) - start) + start).toInt()

Usado assim:

// will return an `Int` between 0 and 10 (incl.)
(0..10).random()
s1m0nw1
fonte
4

Outra maneira de implementar a resposta de s1m0nw1 seria acessá-la através de uma variável. Não que seja mais eficiente, mas evita que você precise digitar ().

val ClosedRange<Int>.random: Int
    get() = Random().nextInt((endInclusive + 1) - start) +  start 

E agora ele pode ser acessado como tal

(1..10).random
Quinn
fonte
3

No Kotlin 1.3, você pode fazê-lo como

val number = Random.nextInt(limit)
divergente
fonte
2

Não existe um método padrão que faça isso, mas você pode facilmente criar o seu próprio usando Math.random()a classe ou java.util.Random. Aqui está um exemplo usando o Math.random()método:

fun random(n: Int) = (Math.random() * n).toInt()
fun random(from: Int, to: Int) = (Math.random() * (to - from) + from).toInt()
fun random(pair: Pair<Int, Int>) = random(pair.first, pair.second)

fun main(args: Array<String>) {
    val n = 10

    val rand1 = random(n)
    val rand2 = random(5, n)
    val rand3 = random(5 to n)

    println(List(10) { random(n) })
    println(List(10) { random(5 to n) })
}

Esta é uma saída de amostra:

[9, 8, 1, 7, 5, 6, 9, 8, 1, 9]
[5, 8, 9, 7, 6, 6, 8, 6, 7, 9]
Mahdi AlKhalaf
fonte
2

A lib padrão do Kotlin não fornece a API Random Number Generator. Se você não estiver em um projeto de multiplataforma, é melhor usar a API da plataforma (todas as outras respostas da pergunta falam sobre esta solução) .

Mas se você estiver em um contexto de multiplataforma, a melhor solução é implementar aleatoriamente sozinho no puro kotlin para compartilhar o mesmo gerador de números aleatórios entre plataformas. É mais simples para desenvolvedores e testes.

Para responder a esse problema no meu projeto pessoal, implementei um gerador de congruência linear Kotlin puro . LCG é o algoritmo usado por java.util.Random. Siga este link se desejar usá-lo: https://gist.github.com/11e5ddb567786af0ed1ae4d7f57441d4

Meu objetivo de implementação nextInt(range: IntRange)para você;).

Tome cuidado com o meu objetivo, o LCG é bom para a maioria dos casos de uso (simulação, jogos, etc ...), mas não é adequado para uso criptográfico devido à previsibilidade desse método.

Valentin Michalak
fonte
Prefiro confiar no código específico da plataforma do que criar meu próprio algoritmo aleatório. Isso me lembra um pouco o código do java.util.Random, mas não corresponde completamente.
Simon Forsberg
2

Se os números que você deseja escolher não forem consecutivos, você pode usar random().

Uso:

val list = listOf(3, 1, 4, 5)
val number = list.random()

Retorna um dos números que estão na lista.

Willi Mentzel
fonte
2

Não é mais necessário usar funções de extensão personalizadas. O IntRange agora possui uma random()função de extensão pronta para uso.

val randomNumber = (0..10).random()
Willi Mentzel
fonte
2

Usando uma função de nível superior, você pode obter exatamente a mesma sintaxe de chamada que no Ruby (como desejar):

fun rand(s: Int, e: Int) = Random.nextInt(s, e + 1)

Uso:

rand(1, 3) // returns either 1, 2 or 3
Willi Mentzel
fonte
1

Primeiro, você precisa de um RNG. No Kotlin, você atualmente precisa usar os específicos da plataforma (não há um Kotlin embutido em um). Para a JVM é java.util.Random. Você precisará criar uma instância e depois chamar random.nextInt(n).

Mibac
fonte
1

Para obter um número Int aleatório no Kotlin, use o seguinte método :

import java.util.concurrent.ThreadLocalRandom

fun randomInt(rangeFirstNum:Int, rangeLastNum:Int) {
    val randomInteger = ThreadLocalRandom.current().nextInt(rangeFirstNum,rangeLastNum)
    println(randomInteger)
}
fun main() {    
    randomInt(1,10)
}


// Result – random Int numbers from 1 to 9

Espero que isto ajude.

Andy Fedoroff
fonte
0

Você pode criar uma função de extensão:

infix fun ClosedRange<Float>.step(step: Float): Iterable<Float> {
    require(start.isFinite())
    require(endInclusive.isFinite())
    require(step.round() > 0.0) { "Step must be positive, was: $step." }
    require(start != endInclusive) { "Start and endInclusive must not be the same"}

    if (endInclusive > start) {
        return generateSequence(start) { previous ->
            if (previous == Float.POSITIVE_INFINITY) return@generateSequence null
            val next = previous + step.round()
            if (next > endInclusive) null else next.round()
        }.asIterable()
    }

    return generateSequence(start) { previous ->
        if (previous == Float.NEGATIVE_INFINITY) return@generateSequence null
        val next = previous - step.round()
        if (next < endInclusive) null else next.round()
    }.asIterable()
}

Valor flutuante redondo:

fun Float.round(decimals: Int = DIGITS): Float {
    var multiplier = 1.0f
    repeat(decimals) { multiplier *= 10 }
    return round(this * multiplier) / multiplier
}

Uso do método:

(0.0f .. 1.0f).step(.1f).forEach { System.out.println("value: $it") }

Resultado:

valor: 0.0 valor: 0.1 valor: 0.2 valor: 0.3 valor: 0.4 valor: 0.5 valor: 0.6 valor: 0.7 valor: 0.8 valor: 0.9 valor: 1.0

rodrigosimoesrosa
fonte
0

Código fonte completo. Pode controlar se duplicatas são permitidas.

import kotlin.math.min

abstract class Random {

    companion object {
        fun string(length: Int, isUnique: Boolean = false): String {
            if (0 == length) return ""
            val alphabet: List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9') // Add your set here.

            if (isUnique) {
                val limit = min(length, alphabet.count())
                val set = mutableSetOf<Char>()
                do { set.add(alphabet.random()) } while (set.count() != limit)
                return set.joinToString("")
            }
            return List(length) { alphabet.random() }.joinToString("")
        }

        fun alphabet(length: Int, isUnique: Boolean = false): String {
            if (0 == length) return ""
            val alphabet = ('A'..'Z')
            if (isUnique) {
                val limit = min(length, alphabet.count())
                val set = mutableSetOf<Char>()
                do { set.add(alphabet.random()) } while (set.count() != limit)
                return set.joinToString("")
            }

            return List(length) { alphabet.random() }.joinToString("")
        }
    }
}
Vincent Sit
fonte
0

Sempre que houver uma situação em que você queira gerar um endereço chave ou mac, que seja um número hexadecimal com dígitos com base na demanda do usuário e que também use o android e o kotlin, o código abaixo ajudará você:

private fun getRandomHexString(random: SecureRandom, numOfCharsToBePresentInTheHexString: Int): String {
    val sb = StringBuilder()
    while (sb.length < numOfCharsToBePresentInTheHexString) {
        val randomNumber = random.nextInt()
        val number = String.format("%08X", randomNumber)
        sb.append(number)
    }
    return sb.toString()
} 
Rupesh Gaud
fonte
-1

ser super duper))

 fun rnd_int(min: Int, max: Int): Int {
        var max = max
        max -= min
        return (Math.random() * ++max).toInt() + min
    }
Deomin Dmitriy
fonte