#android-studio #sorting #kotlin #random
Вопрос:
У меня есть вопрос, как предотвратить повторение случайных чисел. Кстати, может ли кто-нибудь объяснить мне, как сортировать эти случайные числа?
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.textView)
val button = findViewById<Button>(R.id.buttom)
button.setOnClickListener {
var liczba = List(6){Random.nextInt(1,69)}
textView.text = liczba.toString()
}
}
Комментарии:
1. Вы можете позвонить
sorted
по списку, чтобы получить отсортированную версию (илиsort
по aMutableList
, если вы хотите отсортировать ее на месте).2. вы также можете создать изменяемый список, чтобы добавлять каждое новое случайное число и проверять, нет ли вновь сгенерированного случайного числа в вашем сгенерированном списке. Если это произойдет, вы отбросите это, можете снова позвонить случайным образом.
Ответ №1:
Существует три основных метода, позволяющих избежать повторения «случайных» чисел. Если они не повторяются, то, конечно, на самом деле они не случайны.
- с небольшим диапазоном чисел произвольно перетасуйте числа и выберите их по порядку после перетасовки.
- с диапазоном чисел среднего размера запишите выбранные вами числа и отклоните любые повторения. Это будет происходить медленно, если вы выберете большой процент доступных номеров.
- при очень большом диапазоне чисел вам нужно что-то вроде шифрования: сопоставление один к одному, которое сопоставляет 0, 1, 2, 3 … к числам в (большом) диапазоне. Например, 128-битное шифрование даст явно случайный порядок неповторяющихся 128-битных чисел.
Ответ №2:
val size = 6
val s = HashSet<Int>(size)
while (s.size < size) {
s = Random.nextInt(1,69)
}
Ответ №3:
Последовательности-отличный способ генерировать потоки данных и ограничивать или фильтровать результаты.
import kotlin.random.Random
import kotlin.random.nextInt
val randomInts = generateSequence {
// this lambda is the source of the sequence's values
Random.nextInt(1..69)
}
// make the values distinct, so there's no repeated ints
.distinct()
// only fetch 6 values
// Note: It's very important that the source lambda can provide
// this many distinct values! If not, the stream will
// hang, endlessly waiting for more unique values.
.take(6)
// sort the values
.sorted()
// and collect them into a Set
.toSet()
Чтобы убедиться, что это работает, вот тест на основе свойств с использованием Kotest.
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldBeMonotonicallyIncreasing
import io.kotest.matchers.collections.shouldBeUnique
import io.kotest.matchers.collections.shouldHaveSize
import io.kotest.property.Arb
import io.kotest.property.arbitrary.positiveInts
import io.kotest.property.checkAll
import kotlin.random.Random
import kotlin.random.nextInt
class RandomImageLogicTest : FunSpec({
test("expect sequence of random ints is distinct, sorted, and the correct size") {
checkAll(Arb.positiveInts(30)) { limit ->
val randomInts = generateSequence { Random.nextInt(1..69) }
.distinct()
.take(limit)
.sorted()
.toSet()
randomInts.shouldBeMonotonicallyIncreasing()
randomInts.shouldBeUnique()
randomInts.shouldHaveSize(limit)
}
}
})
Испытание проходит!
Test Duration Result
expect sequence of random ints is di... 0.163s passed
Ответ №4:
Подобно ответу @IR42, вы можете сделать что-то вроде этого
import kotlin.random.Random
fun getUniqueRandoms() = sequence {
val seen = mutableSetOf<Int>()
while(true) {
val next = Random.nextInt()
// add returns true if it wasn't already in the set - i.e. it's not a duplicate
if (seen.add(next)) yield(next)
}
}
fun main() {
getUniqueRandoms().take(6).sorted().forEach(::println)
}
Таким getUniqueRandoms
образом, создается независимая последовательность и сохраняет свое собственное внутреннее состояние, из которого получаются числа. Для вызывающего абонента это просто базовая последовательность, которая создает уникальные значения, и вы можете использовать их так, как вам нравится.
Как говорит @rossum, это действительно зависит от того, сколько вы собираетесь произвести — если вы производите много, или эта последовательность действительно долговечна, этот набор видимых чисел со временем станет очень большим. Кроме того, он начнет замедляться по мере того, как вы будете получать все больше и больше столкновений, и вам придется продолжать пытаться найти то, что еще не видели.
Но для большинства ситуаций такого рода вещи просто прекрасны — вы, вероятно, захотите сравнить их, если вы производите, скажем, миллионы чисел, но для чего-то вроде 6 об этом даже не стоит беспокоиться!
Ответ №5:
Я создаю простой класс, в конструкторе вы вводите число «от» (минимально возможное число) и «до» (максимально возможное число), класс создает список чисел. «nextInt()» возвращает случайный элемент из коллекции и удаляет его.
class RandomUnrepeated(from: Int, to: Int) {
private val numbers = (from..to).toMutableList()
fun nextInt(): Int {
val index = kotlin.random.Random.nextInt(numbers.size)
val number = numbers[index]
numbers.removeAt(index)
return number
}
}
использование:
val r = RandomUnrepeated(0,100)
r.nextInt()