In Kotlin, can I have two random values with the second one omitting the first random number? - kotlin

Here is what I am trying to say:
val firstNumbers = (1..69).random()
val secondNumbers = (1..69).random()
I would like the secondNumbers to omit the random number picked in firstNumbers

If you're just generating two numbers, what you could do is lower the upper bound for secondNumbers down to 68, then add 1 if it's greater than or equal to the first number. This will ensure an even distribution:
val firstNumber = (1..69).random()
var secondNumber = (1..68).random()
if (secondNumber >= firstNumber) {
secondNumber += 1
}
For generating more than 2 numbers, the following code should work:
fun randoms(bound: Int, n: Int): List<Int> {
val mappings = mutableMapOf<Int, Int>()
val ret = mutableListOf<Int>()
for (i in 0 until n) {
val num = (1..(bound - i)).random()
ret.add(mappings.getOrDefault(num, num))
mappings.put(num, mappings.getOrDefault(bound - i, bound - i))
}
return ret
}
It tries to emulate Fisher-Yates shuffling while only keeping track of swaps that happened, thus greatly reducing memory usage when n is much less than bound. If n is very close to bound, then the answer by #lukas.j is much cleaner to use and probably also faster.
It can be used like so:
randoms(69, 6) // might return [17, 36, 60, 48, 69, 21]
(I'd encourage people to double-check the uniformity and correctness of the algorithm, but it seems good to me)

random() is the wrong approach, rather use shuffled() and then take the first two elements from the list with take(). And it is a oneliner:
val (firstNumber, secondNumber) = (1..69).shuffled().take(2)
println(firstNumber)
println(secondNumber)

Another approach could be to find one number in range 1..69, remove that number from the range and find the second one.
val first = (1..69).random()
val second = ((1..69) - first).random()
Edit: As per your comment, you want 6 different numbers within this range. You can do that like this.
val values = (1..69).toMutableList()
val newList = List(6) {
values.random().also { values.remove(it) }
}

Related

Write a kotlin program that prints the number that is repeated the most in a consecutive way

I'm kind of stuck, I don't know how to make the second loop to start 1 position above the first loop in Kotlin.
I have an array (named myArray) with 10 elements, I need to Write a Kotlin program that prints the number that has the most consecutive repeated number in the array and also prints the number of times it appears in the sequence.
The program must parse the array from left to right so that if two numbers meet the condition, the one that appears first from left to right will be printed.
Longest: 3
Number: 8
fun main() {
val myArray: IntArray = intArrayOf(1,2,2,4,5,6,7,8,8,8)
for((index , value) in myArray.withIndex()){
var inx = index + 1
var count = 0
var longest = 0
var number = 0
for((inx,element) in myArray.withIndex()) {
if(value == element ){
count+=
}
}
if(longest < count){
longest = count
number = value
}
}
}
I'm against just dropping answers, but it is quite late for me, so I'll leave this answer here and edit it tomorrow with more info on how each part works. I hope that maybe in the meanwhile it will help you to gain some idea to where you might be going wrong.
val results = mutableMapOf<Int, Int>()
(0..myArray.size - 2).forEach { index ->
val current = myArray[index]
if (current == myArray[index + 1]) {
results[current] = (results[current] ?: 1) + 1
}
}
val (max, occurrences) = results.maxByOrNull { it.value } ?: run { println("No multiple occurrences"); return }
println("Most common consecutive number $max, with $occurrences occurrences")
Alternatively if the intArray would be a list, or if we allowed to change it to a list myArray.toList(), you could replace the whole forEach loop with a zipWithNext. But I'm pretty sure that this is a HW question, so I doubt this is the expected way of solving it.
myList.zipWithNext { a, b ->
if (a == b) results[a] = (results[a] ?: 1) + 1
}

What is the most efficient way to generate random numbers from a union of disjoint ranges in Kotlin?

I would like to generate random numbers from a union of ranges in Kotlin. I know I can do something like
((1..10) + (50..100)).random()
but unfortunately this creates an intermediate list, which can be rather expensive when the ranges are large.
I know I could write a custom function to randomly select a range with a weight based on its width, followed by randomly choosing an element from that range, but I am wondering if there is a cleaner way to achieve this with Kotlin built-ins.
Suppose your ranges are nonoverlapped and sorted, if not, you could have some preprocessing to merge and sort.
This comes to an algorithm choosing:
O(1) time complexity and O(N) space complexity, where N is the total number, by expanding the range object to a set of numbers, and randomly pick one. To be compact, an array or list could be utilized as the container.
O(M) time complexity and O(1) space complexity, where M is the number of ranges, by calculating the position in a linear reduction.
O(M+log(M)) time complexity and O(M) space complexity, where M is the number of ranges, by calculating the position using a binary search. You could separate the preparation(O(M)) and generation(O(log(M))), if there are multiple generations on the same set of ranges.
For the last algorithm, imaging there's a sorted list of all available numbers, then this list can be partitioned into your ranges. So there's no need to really create this list, you just calculate the positions of your range s relative to this list. When you have a position within this list, and want to know which range it is in, do a binary search.
fun random(ranges: Array<IntRange>): Int {
// preparation
val positions = ranges.map {
it.last - it.first + 1
}.runningFold(0) { sum, item -> sum + item }
// generation
val randomPos = Random.nextInt(positions[ranges.size])
val found = positions.binarySearch(randomPos)
// binarySearch may return an "insertion point" in negative
val range = if (found < 0) -(found + 1) - 1 else found
return ranges[range].first + randomPos - positions[range]
}
Short solution
We can do it like this:
fun main() {
println(random(1..10, 50..100))
}
fun random(vararg ranges: IntRange): Int {
var index = Random.nextInt(ranges.sumOf { it.last - it.first } + ranges.size)
ranges.forEach {
val size = it.last - it.first + 1
if (index < size) {
return it.first + index
}
index -= size
}
throw IllegalStateException()
}
It uses the same approach you described, but it calls for random integer only once, not twice.
Long solution
As I said in the comment, I often miss utils in Java/Kotlin stdlib for creating collection views. If IntRange would have something like asList() and we would have a way to concatenate lists by creating a view, this would be really trivial, utilizing existing logic blocks. Views would do the trick for us, they would automatically calculate the size and translate the random number to the proper value.
I implemented a POC, maybe you will find it useful:
fun main() {
val list = listOf(1..10, 50..100).mergeAsView()
println(list.size) // 61
println(list[20]) // 60
println(list.random())
}
#JvmName("mergeIntRangesAsView")
fun Iterable<IntRange>.mergeAsView(): List<Int> = map { it.asList() }.mergeAsView()
#JvmName("mergeListsAsView")
fun <T> Iterable<List<T>>.mergeAsView(): List<T> = object : AbstractList<T>() {
override val size = this#mergeAsView.sumOf { it.size }
override fun get(index: Int): T {
if (index < 0 || index >= size) {
throw IndexOutOfBoundsException(index)
}
var remaining = index
this#mergeAsView.forEach { curr ->
if (remaining < curr.size) {
return curr[remaining]
}
remaining -= curr.size
}
throw IllegalStateException()
}
}
fun IntRange.asList(): List<Int> = object : AbstractList<Int>() {
override val size = endInclusive - start + 1
override fun get(index: Int): Int {
if (index < 0 || index >= size) {
throw IndexOutOfBoundsException(index)
}
return start + index
}
}
This code does almost exactly the same thing as short solution above. It only does this indirectly.
Once again: this is just a POC. This implementation of asList() and mergeAsView() is not at all production-ready. We should implement more methods, like for example iterator(), contains() and indexOf(), because right now they are much slower than they could be. But it should work efficiently already for your specific case. You should probably test it at least a little. Also, mergeAsView() assumes provided lists are immutable (they have fixed size) which may not be true.
It would be probably good to implement asList() for IntProgression and for other primitive types as well. Also you may prefer varargs version of mergeAsView() than extension function.
As a final note: I guess there are libraries that does this already - probably some related to immutable collections. But if you look for a relatively lightweight solution, it should work for you.

Idiomatically group String (count consecutively repeated characters)

How with what idioms do I achieve the desired effect?
val input = "aaaabbbcca"
val result = input.(here do the transformations)
val output = listOf("a" to 4, "b" to 3, "c" to 2, "a" to 1)
assert(result == output)
Here's a fun way to do it immutably using fold
fun main() {
val result = "aaaabbbcca"
.chunked(1)
.fold(emptyList<Pair<String, Int>>()) { list, current ->
val (prev, count) = list.lastOrNull() ?: Pair(current, 0)
if (prev == current) list.dropLast(1) + Pair(current, count + 1)
else list + Pair(current, 1)
}
val output = listOf("a" to 4, "b" to 3, "c" to 2, "a" to 1)
check(result == output)
println(result)
}
Output:
[(a, 4), (b, 3), (c, 2), (a, 1)]
This is a tricky little problem, and I can't find a particular idiomatic solution.
However, here's one that's quite concise:
val result = input.replace(Regex("(.)(?!\\1)(.)"), "$1§$2")
.split("§")
.map{ Pair(it[0], it.length) }
It uses a complicated little regex to insert a marker character (§ here, though of course it would work with any character that can't be in the input) between every pair of different characters.  ((?…) is a zero-width look-ahead assertion, so (?!\1) asserts that the next character is different from the previous one.  We need to include the next character in the match, otherwise it'll append a marker after the last character too.)
That gives aaaa§bbb§cc§a in this case.
We then split the string at the marker, giving a list of character groups (in this case "aaaa", "bbb", "cc", "a"), which it's easy to convert into (character,length) pairs.
Using a regex is not always a good solution, especially when it's complicated and unintuitive like this one.  So this might not be a good choice in production code.  On the other hand, a solution using fold() or reduce() probably wouldn't be that much easier to read, either.  In fact, the most maintainable solution might be the old-fashioned one of looping over the characters…
I believe there are no good (efficient, readable) idiomatic ways to solve this. We can use a good, old and boring loop approach. To make it at least a little more funny, we can do it with a lazy computing, utilizing coroutines:
fun String.countConsecutive() = sequence {
if (isEmpty()) return#sequence
val it = iterator()
var curr = it.next()
var count = 1
it.forEach {
if (curr == it) {
count++
} else {
yield(curr.toString() to count)
curr = it
count = 1
}
}
yield(curr.toString() to count)
}
This is good if our string is very long and we only need to iterate over consecutive groups. Even better if we don't need to iterate over all of them.

Generating unique random values with SecureRandom

i'm currently implementing a secret sharing scheme.(shamir)
In order to generate some secret shares, I need to generate some random numbers within a range. FOr this purpose, I have this very simple code:
val sharesPRG = SecureRandom()
fun generateShares(k :Int): List<Pair<BigDecimal,BigDecimal>> {
val xs = IntArray(k){ i -> sharesPRG.nextInt(5)}
return xs
}
I have left out the part that actually creates the shares as coordinates, just to make it reproduceable, and picked an arbitrarily small bound of 5.
My problem is that I of course need these shares to be unique, it doesnt make sense to have shares that are the same.
So would it be possible for the Securerandom.nextint to not return a value that it has already returned?
Of course I could do some logic where I was checking for duplicates, but I really thought there should be something more elegant
If your k is not too large you can keep adding random values to a set until it reaches size k:
fun generateMaterial(k: Int): Set<Int> = mutableSetOf<Int>().also {
while (it.size < k) {
it.add(sharesPRG.nextInt(50))
}
}
You can then use the set as the source material to your list of pairs (k needs to be even):
fun main() {
val pairList = generateMaterial(10).windowed(2, 2).map { it[0] to it[1] }
println(pairList)
}

How can I get the coefficients from a polynomial expression?

At the input I get a polynomial as a string, for example "7x^4+3x^3-6x^2+x-8". I want to get its coefficients in variables but I have no idea on how to do this. Maximum degree is not known, coefficients are integers. Also terms of some degree can be absent. I will be very grateful for any help.
I tried to split by "+" and "-" and then by "x^" but I have trouble with x, the term with (unwritten) degree 1.
Also I have tried firstly split by "x" then by "^" and handled exception with "-" but I don't know how to handle exception with missing degrees.
private fun koef(text: String) : List<Int> {
val vars = text.split("x")
val koefList = mutableListOf<Int>()
var count = 1
vars.forEach {
if (it == "-") koefList.add(-1)
else {
if (it[0] == '^')
}
}
return koefList
}
Here's one implementation.
It's slightly more general, allowing the terms to be in any order, and to have surrounding whitespace.  But it still assumes that the polynomial is valid, that the powers are non-negative and all different, and that there's at least one term.
You didn't specify the order of coefficients, so this returns them in increasing power (starting with that of x^0, then x^1, &c).
private fun coeffs(polynomial: String): List<Int> {
val terms = polynomial.split(Regex("(?=[+-])")).associate{ term ->
val s = term.split(Regex("x\\^?"))
val coeff = s[0].replace(" ", "")
.let{ when (it){ "", "+" -> 1; "-" -> -1; else -> it.toInt() }}
val power = s.getOrNull(1)?.trim()
.let{ when (it){ null -> 0; "" -> 1; else -> it.toInt() }}
power to coeff
}
val highestPower = terms.keys.max()!!
return (0..highestPower).map{ terms[it] ?: 0 }
}
Sample results:
coeffs("x^2+2x-1") = [-1, 2, 1]
coeffs("2x^3 - 3x^4 - x + 4") = [4, -1, 0, 2, -3]
coeffs("x") = [0, 1]
coeffs("-2") = [-2]
It starts by splitting the string into terms.  ((?=[+-]) is a lookahead, which matches an empty string if it's followed by + or -.  Full documentation on Java/Kotlin regular expressions is here.)
It then splits each term into a coefficient and power, converts them to numbers, and creates a Map from term to coefficient.  (That's quite awkward, as it has to handle several special cases where the numbers and/or signs are missing.)  Using a map handles missing powers (and also powers that aren't in order).
Finally, it finds the largest power, and converts the map to a list of coefficients in increasing powers, filling in 0 for missing powers.
I've kept the code short, to show the principle.  If it were to be used in production, you should probably make it safer and more efficient, e.g. by checking for invalid input such as empty string, invalid characters, or duplicate powers; and by putting the Regexs in properties so that they don't have to be recreated each time.  Some unit tests wouldn't be a bad thing, either!