Kotlin: Get Values of a Range in another Range - kotlin

Hello im trying to write a function that compares to ranges and returns the value of the first range in the second.
Example : Range A is (22.0..24.0) Range B ( 20.0..26.0)
so in that case the return value should be 2.0
if Range B is (23.0..26.0) it should return 1.0
How can i do this?

You could write a function like this:
fun ClosedRange<Double>.containedIn(other: ClosedRange<Double>) =
(min(endInclusive, other.endInclusive) - max(start, other.start))
.coerceAtLeast(0.0)
And then use it like this:
val rangeA = 22.0..24.0
val rangeB = 20.0..26.0
val rangeC = 23.0..26.0
println(rangeA.containedIn(rangeB))
println(rangeA.containedIn(rangeC))
Result:
2.0
1.0
Note: you should also import the min/max functions:
import kotlin.math.max
import kotlin.math.min

What you're doing here is taking the intersection (overlap) of two ranges, and calculating its size.  So, building on what Adam Millerchip and cactustictacs have already done, I think I'd break the problem down into simpler parts: min, max, and size properties for a range, and an intersect function that calculates the common subrange of two ranges (if there is one):
val ClosedFloatingPointRange<Double>.min
get() = minOf(start, endInclusive)
val ClosedFloatingPointRange<Double>.max
get() = maxOf(start, endInclusive)
val ClosedFloatingPointRange<Double>.size
get() = max - min
infix fun ClosedFloatingPointRange<Double>.intersect(other: ClosedFloatingPointRange<Double>)
= if (min <= other.max && other.min <= max)
maxOf(min, other.min).rangeTo(minOf(max, other.max))
else
null
With those, you can do e.g.:
val a = 22.0 .. 24.0
val b = 20.0 .. 26.0
println(a intersect b)
println((a intersect b)?.size)
Having the size explicit and separate from the intersection makes each one easier to understand, easier to test, and easier to reuse.  And having intersect return null if there's no overlap is safer.
(This should work for negative numbers and for descending ranges; the intersection is always given as ascending.  This assumes Double ranges; it could be made to handle other types too, though the type parameters get messy.)
TBH, I'm a little surprised that none of those are in the standard library…

Ok well
Range some what act as a list so the the could do like
val r1 = (22.0)..(25.0)
val r2 = (23.0)..(30.0)
val findRangeOfFirstElement = (r1.start -r2.start)

Related

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

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) }
}

Take maximum of multiple function calls

Let's say I have the function fun someValue() : Double.
I want to run this function n times and take the maximum of all the results.
I know I can safe it all in a list and use max(), but I don't want to waste that space (because it actually returns a bigger object).
Does there exist a library-function for this?
Maybe something like repeat(n){someValue()}.max()
Here are a couple of ways that don't allocate an intermediate array or list of all the values.
var x = someValue()
repeat(n - 1) {
x = max(x, someValue())
}
val y = (1 until n).fold(someValue()) { acc, _ -> max(acc, someValue()) }

Group numbers into different ranges

I'm new to Kotlin and I'm trying to solve some problem.
I have a list with the following object:
data class Route(duration: Int)
I want to create a map that will group those trips according to the range of the duration (e.g. 0-9 are single group, 10-19 the next, 20-29, and so on...)
for example, the result of this list:
listOf(Route(5), Route(7), Route(31))
should be the following map:
0..9 to listOf(Route(5), Route(7))
30..39 to listOf(Route(31))
I searched and I've seen that I can put the range into groupBy - however, this is a const range. how can I group by different ranges?
You can use the groupBy function to do that.
fun createRangeOfTen(number: Int): IntRange {
val trunc = number / 10
val lowerBound = trunc * 10
val upperBound = lowerBound + 9
return lowerBound..upperBound
}
val list = listOf(
Route(5), Route(7), Route(31)
)
val map = list.groupBy({ createRangeOfTen(it.duration) }, { it })
println(map)
// {0..9=[Route(duration=5), Route(duration=7)], 30..39=[Route(duration=31)]}

Error in Print prime number using high order functions in kotlin

val listNumbers = generateSequence(1) { it + 1 }
val listNumber1to100 = listNumbers.takeWhile { it < 100 }
val secNum:Unit = listNumber1to100.forEach {it}
println(listNumber1to100.asSequence().filter { it%(listNumber1to100.forEach { it })!=0 }.toList())
I have an error in reminder sign!
This is Error: None of the following functions can be called with the arguments supplied
In your first approach, the error appears in this line:
it%(listNumber1to100.forEach { it })
A Byte, Double, Float, Int, Long or Short is prefered right after the % operator, however, forEach is a function which the return type is Unit.
In your second approach, you have the correct expression in isPrime(Int). Here are some suggestions for you:
listNumber1to100 is excluding 100 in your code, if you want to include 100 in listNumber1to100, the lambda you pass to takeWhile should be changed like this:
val listNumber1to100 = listNumbers.takeWhile { it <= 100 }
listNumber1to100.asSequence() is redundant here since listNumber1too100 is itself a TakeWhileSequence which implements Sequence.
isPrime(Int) is a bit confusing since it is check for isComposite and it does not work for every input it takes(it works for 1 to 99 only). I will rewrite it in this way:
fun isPrime(num: Int): Boolean = if (num <= 1) false else !(2..num/2).any { num % it == 0 }
Since prime number must be positive and 1 is a special case(neither a prime nor composite number), it just return false if the input is smaller or equal to 1. If not, it checks if the input is divisible by a range of number from 2 to (input/2). The range ends before (input/2) is because if it is true for num % (num/2) == 0, it is also true for num % 2 == 0, vise versa. Finally, I add a ! operator before that because a prime number should not be divisible by any of those numbers.
Finally, you can filter a list by isPrime(Int) like this:
println(listNumber1to100.filter(::isPrime).toList())
PS. It is just for reference and there must be a better implementation than this.
To answer your question about it, it represents the only lambda parameter inside a lambda expression. It is always used for function literal which has only one parameter.
The error is because the expression: listNumber1to100.forEach { it } - is not a number, it is a Unit (ref).
The compiler try to match the modulo operator to the given function signatures, e.g.: mod(Byte) / mod(Int) / mod(Long) - etc.
val listNumbers = generateSequence(1) { it + 1 }
val listNumber1to100 = listNumbers.takeWhile { it < 100 }
fun isPrime(num: Int): Boolean = listNumber1to100.asSequence().any { num%it==0 && it!=num && it!=1 }
println(listNumber1to100.asSequence().filter { !isPrime(it)}.toList())
I found this solution and worked
But why can I have a non-number here in the right side of reminder

Checking for equality in lists in SML

i want to write a function that checks for equality of lists in SML
for instance :
[1,2,3]=[1,2,3];
val it = true : bool
So instead of writing down the whole thing, i want to make a function that takes two predefined lists, and compare them, so that if list01 is [1,2,3] and list09 is [1,2,3]
then fun equal (list01, list09); will return -val it = true : bool;
You seem to be aware that = works on lists, so (as I already said in my comment) I don't see why you need to define an equal function.
That being said, you can just write:
fun equal (a, b) = (a = b);
Here is a not checked sample:
fun compare ([], []) = true # both empty
| compare (x::xs, y::ys) = (x = y) and compare(xs,ys)
| compare (_, _) = false # different lengths