Getting Time range between non intersecting ranges - kotlin

I have the following timelines :
7 a.m --------------------- 12 a.m. 2 am .................. 10 a.m
10-------11 3------5
closed closed
the output should be the non-intersecting time ranges:
7-10 a.m, 11 -12 a.m, 2-3 p.m, 5-10 p.m
I tried to minus and subtract method for Ranges but didn't work
A tricky part could be the following case
7 a.m --------------------- 12 a.m. 2 am .................. 10 a.m
10----------------------------------------5
closed
the output should be the non-intersecting time ranges:
7-10 a.m, 5-10 p.m
Any Idea for kotlin implementation?
I tried to minus and subtract method for Ranges but didn't work

Sounds like a pretty common case and I suspect there are some existing algorithms for it, but nothing comes out of top of my head.
My idea is to first transform both lists of ranges into a single list of opening/closing "events", ordered by time. The start of an opening range increases the "openess" by +1 while its end decreases it (-1). Start of a closing range also decreases "openess" while its end increases it. Then we iterate the events in the time order, keeping the information on what is the current "openess" level. Whenever the "openess" level is 1, that means we are in the middle of an opening range, but not inside a closing range, so we are entirely open.
Assuming both lists of ranges are initially properly ordered, as in your example, I believe it should be doable in linear time and even without this intermediary list of events. However, such implementation would be pretty complicated to cover all possible states, so I decided to go with a simpler solution which is I believe O(n * log(n)). Also, this implementation requires that opening ranges do not overlap with each other, the same for closing ranges:
fun main() {
// your first example
println(listOf(Range(7, 12), Range(14, 22)) - listOf(Range(10, 11), Range(15, 17)))
// second example
println(listOf(Range(7, 12), Range(14, 22)) - listOf(Range(10, 17)))
// two close rangs "touch" each other
println(listOf(Range(8, 16)) - listOf(Range(10, 11), Range(11, 13)))
// both open and close range starts at the same time
println(listOf(Range(8, 16)) - listOf(Range(8, 12)))
}
data class Range(val start: Int, val end: Int)
operator fun List<Range>.minus(other: List<Range>): List<Range> {
// key is the time, value is the change of "openess" at this time
val events = sortedMapOf<Int, Int>()
forEach { (start, end) ->
events.merge(start, 1, Int::plus)
events.merge(end, -1, Int::plus)
}
other.forEach { (start, end) ->
events.merge(start, -1, Int::plus)
events.merge(end, 1, Int::plus)
}
val result = mutableListOf<Range>()
var currOpeness = 0
var currStart = 0
for ((time, change) in events) {
// we were open and now closing
if (currOpeness == 1 && change < 0) {
result += Range(currStart, time)
}
currOpeness += change
// we were closed and now opening
if (currOpeness == 1 && change > 0) {
currStart = time
}
}
return result
}

Related

The problem of different result values ​due to capturing in Kotlin sequence

If a value called prime is declared externally in the problem code, Capturing occurs, resulting in different results. Can someone tell me in detail why the result value is different when capturing occurs?
normal code
val primes: Sequence<Int> = sequence {
var numbers = generateSequence(2) { it + 1 }
while (true) {
val prime = numbers.first()
yield(prime)
numbers = numbers.drop(1)
.filter {
it % prime != 0
}
}
}
println(primes.take(10).toList()) // [2, 3, 5, 7. 11, 13, 17, 19, 23, 29]
problem code
val primes: Sequence<Int> = sequence {
var numbers = generateSequence(2) { it + 1 }
var prime: Int
while (true) {
prime = numbers.first()
yield(prime)
numbers = numbers.drop(1)
.filter {
it % prime != 0
}
}
}
println(primes.take(10).toList()) // [2, 3, 5, 6, 7, 8, 9, 10, 11, 12]
Lambda capture occurs when using sequences
When you call the method filter { it % prime != 0 } you permanently attach one filter, with its lambda function, to the numbers Sequence object. The value of prime in that lambda is captured from the enclosing code. With each loop, more and more filters are attached to the numbers Sequence.
In the first (working) example, each time a filter lambda is attached to the numbers Sequence, it gets its own unique version of the prime variable. Specifically, it gets the unique val prime that is defined at the start of the while loop in which that filter lambda is attached. That's just what you want.
In the second (broken) example, there is only one prime variable throughout the program: the var prime defined outside the loop. It changes every time the while loop runs. That means that every filter lambda is identical at any point in time: they all use the same prime value, being the last number taken off the front of the (chopped) numbers sequence. And prime keeps going up by one with each iteration. All in all, it means with each loop all the identical filter lambda functions also change and so have no discernible effect on the numbers sequence, or in turn the sequence printed to the screen.
Because the filter method is evaluated lazily, every iteration of the loop again and again. In the first code block, you define prime locally so that's what's captured. In the second block, it knows prime is reassigned every time, so it'll only look at the latest value.

how to perform dynamic subtraction of a list of numbers with a specific value

My idea is to subtract each value from my list through the value of a variable, for example:
var subtraction = 250
var list = mutableListOf(300, 200, 100)
Then, using the 250 of the subtraction variable,
you can dynamically subtract each value of the item,
from the last to the first, so with that 250 the program should return: -> list(300, 50).
Where 250 is subtracted from item 100 (last item) and then "150" remains from the value "250",
and the remaining 150 is subtracted from 200 (second item) and remains 50,
thus zeroing out the value of "250" and the program stop.
Getting (300, 50) -> 50 which comes from 200 (second item).
As if I was going through my list of numbers, subtracting item by item through the value of a variable, from last to first.
Your question still needs further clarification:
What should be the output if subtraction = 700?
What should be the output if subtraction = 600?
What should be the output if subtraction = 100?
The following can be a starting point to solve your question:
fun subtraction() {
var subtraction = 250
var list = mutableListOf(300, 200, 100)
// Loop the list in Reverse order
for (number in list.indices.reversed()) {
subtraction -= list[number] // Subtract the last number
// If subtraction is greater than zero, continue and remove the last element
if (subtraction > 0)
list.removeAt(number)
else {
// It subtraction is less than or equal to zero,
// remove the last element, append the final subtraction result,
// and stop the loop
list.removeAt(number)
list.add(abs(subtraction))
break
}
}
// If the subtraction result is still positive after whole list has been processed,
// append it back to the list
// if (subtraction > 0)
// list.add(subtraction)
println(list)
}
Output
[300, 50]
The question isn't very clear, but as I understand it: OP wants to modify a list of numbers, subtracting a fixed amount from each, and removing those for which the result would be negative.
If so, it can be done very simply:
list.replaceAll{ it - subtraction }
list.removeIf{ it < 0 }
However, instead of mutating the existing list, it would probably be more common to create a new one:
val newList = list.map{ it - subtraction }.filter{ it >= 0 }
Or, if you need to avoid creating a temporary list:
val newList = list.mapNotNull{ (it - subtraction).takeIf{ it >= 0 } }
A solution with foldRight using a Pair as accumulator:
val list = listOf(300, 200, 100)
val subtraction = 250
val result = list
.foldRight(subtraction to emptyList<Int>()) { item, (diff, list) ->
when {
diff > item -> diff - item to emptyList()
else -> 0 to listOf(item - diff) + list
}
}
.second
println(result) // Output: [300, 50]

How to setup for each loop in Kotlin to avoid out of bounds exception

In java I got this construction
for (let i = 0; i < x.length-1; I++
And here to avoid outOfBoundsException we are using x.length-1 but how to do the same thing in Kotlin? I got this code so far
x.forEachIndexed { index, _ ->
output.add((x[index+1]-x[index])*10)
}
And it crashes on the last element when we call x[index+1] so I need to handle the last element somehow
Input list
var x = doubleArrayOf(0.0, 0.23, 0.46, 0.69, 0.92, 1.15, 1.38, 1.61)
For a classic Java for loop you got two options in Kotlin.
One would be something like this.
val x = listOf(1,2,3,4)
for (i in 0 .. x.lastIndex){
// ...
}
Using .. you basically go from 0 up to ( and including) the number coresponding to the second item, in this case the last index of the list.( so from 0 <= i <= x.lastIndex)
The second option is using until
val x = listOf(1,2,3,4)
for (i in 0 until x.size){
// ...
}
This is similar to the previous approach, except the fact that until is not inclusive with the last element.(so from 0 <= i < x.size ).
What you probably need is something like this
val x = listOf(1,2,3,4)
for (i in 0 .. x.lastIndex -1){
// ...
}
or alternative, using until, like this
val x = listOf(1,2,3,4)
for (i in 0 until x.size-1){
// ...
}
This should probably avoid the IndexOut of bounds error, since you go just until the second to last item index.
Feel free to ask more if something is not clear.
This is also a great read if you want to learn more about ranges. https://kotlinlang.org/docs/ranges.html#progression
You already have an answer, but this is another option. If you would use a normal list, you would have access to zipWithNext(), and then you don't need to worry about any index, and you can just do:
list.zipWithNext { current, next ->
output.add((next - current)*10)
}
As mentioned by k314159, we can also do asList() to have direct access to zipWithNext and other list methods, without many drawbacks.
array.asList().zipWithNext { current, next ->
output.add(next - current)
}

Compare value against two values with 'or' operator

I have a simple if () condition which needs to check if value is either 1 or 2 (for example). Let's say the value we are comparing against is not 'simple':
if(it.first().property.value == 1 || it.first().property.value == 2) {
// Do stuff
}
Is there a better way to perform this check (without typing the entire expression to get the actual value twice)? The only thing that comes to mind is
if(listOf(1, 2).contains(it.first().property.value)) {
// Do stuff
}
But I'm afraid it's more memory consuming since it has additional list introduced.
Your last suggestion is a good one in general, though it's usually better to use a predefined list (and the in operator):
// At the top level, or in a (companion) object:
val acceptableValues = listOf(1, 2)
// Then in the relevant part of the code:
if (it.first().property.value in acceptableValues)
// Do stuff
That only allocates the list once, and performance is about as good as any other option.  It's also very readable, and general.
(If the list doesn't naturally fit into a named property, you'd have to judge how often it might be needed, in order to trade a minor performance benefit against the conciseness of putting it directly in the condition.)
In fact, because you're looking for consecutive integers, there's a more concise option for this particular test:
if (it.first().property.value in 1..2)
// Do stuff
That would work whenever the acceptable values form an (uninterrupted) range.
Alternatively, if you're always checking against exactly two values, you could write a simple extension function:
fun <T> T.isEither(a: T, b: T) = this == a || this == b
(You could write a more general one using a vararg param, but that would create an array each time — very similar to the in listOf() case we started with.)
You can decide it using a when expression like in this example:
fun main() {
val number = 22
when (number) {
1, 2 -> println("${number} is 1 or 2")
in 10..20 -> println("${number} is between 10 and 20 (inclusively)")
else -> println("${number} is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above")
}
}
The output here is
22 is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above
You could define an extension function on the type of it to make it more readable:
if(it.isOneOrTwo()) {
// Do stuff
}
Not sure what's the type of your it, replace TYPEOFIT accordingly:
private inline fun TYPEOFIT.isOneOrTwo() = first().property.value == 1 || first().property.value == 2
To additionally improve the condition you could leverage when:
private inline fun TYPEOFIT.isOneOrTwo() = when(first().property.value) {
1,2 -> true
else -> false
}

kotlin intProgression not iterating?

Sorry this seems very basic but I'm missing something
I have a method signature override
fun doSomeWork (range: IntProgression, j: Int): List<Cell>{
I want to iterate the range whatever it is (could be up or down say 1 to 4 or 4 down to 1). The range itself seems to work, so on my 4 down to 1 example
println (range.first.toString() + " to " + range.last.toString() + ", step = " + range.step)
prints "4 to 1, step = 1"
but I can't seem to iterate the range ? I've tried a few things
for (i in range) {
println ("range: $i)"
}
and then
for (i in range.first until range.last step range.step){
println ("Loop de loop $i")
}
(although writing this question I noticed it is step 1 not -1 which may be the issue here ? but as I want to be able to pass in a range of either direction I haven't checked)
and then
range.forEach { println ("range foreach") }
none of them print anything, but they don't throw an error so any code after that runs through properly.
Can anyone point out why I'm failing to do this entry level task ?!
So you want an IntProgression from 4 to 1 with step -1, i.e. IntProgression.fromClosedRange(4, 1, -1) or better yet: 4.downTo(1). While you wrote your question you already realised the step... but the starting point isn't 1 then, but rather 4 ;-) With the downTo such problems will not arise, as the function takes care of the direction and it's also more readable then.
Note also that you can simply use reversed to reverse a progression:
range.reversed()
and either use it in a for-loop or with .forEach, etc.
So:
val range = IntProgression.fromClosedRange(1, 4, 1)
range.forEach(::print) // prints: 1234
range.reversed().forEach(::print) // prints: 4321
The forEach method can be used to iterate through the IntProgression. The it can be used to get the value or index.
fun doSomeWork (range: IntProgression) {
range.forEach {
println(it)
}
}
Invoking the above method:-
ClassName().doSomeWork(IntProgression.fromClosedRange(1,10, 1))
val range= IntProgression.fromClosedRange(1, 4, 1)
for (i in range)
println(i) // out put 1234
for (i in range.reversed())
println(i)//out put 4321
use
IntProgression.fromClosedRange(start, end, step)
for reverse range
IntProgression.reversed()
more details refer Ranges