Group numbers into different ranges - kotlin

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

Related

How to get the difference betweeen two dates (jetpack compose/kotlin)?

I have to calculate how many days are left between the date selected by the user through a DatePicker and the current date
I was trying to write something like this:
val simpleDate = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
val date = simpleDate.parse(event!!.date!!)
val diff = Duration.between(LocalDate.now(), date.toInstant())
val leftDays = diff.toDays()
Your mix of outdated (SimpleDateFormat, 'Date') and modern (LocalDate) APIs is not optimal, I think:
I would use plain java.time here, because…
you can obviously use it in your application
it has a specific class for datetime Strings of the pattern you have shown in your question: an OffsetDateTime and
there's a java.time.Duration which you have tried to use
Here's an example:
fun main(args: Array<String>) {
// example input, some future datetime
val input = "2022-12-24T13:22:51.837Z"
// parse that future datetime
val offsetDateTime = OffsetDateTime.parse(input)
// build up a duration between the input and now, use the same class
val duration = Duration.between(OffsetDateTime.now(), offsetDateTime)
// get the difference in full days
val days = duration.toDays()
// print the result as "days left"
println("$days days left")
}
Output:
110 days left
If you don't receive a datetime but a date without time (just day of month, month of year and year), then use a LocalDate and calculate the ChronoUnit.DAYS.between(today, futureDate)
fun main(args: Array<String>) {
// example input, some future date
val input = "2022-12-24"
// parse that
val futureDate = LocalDate.parse(input)
// get the difference in full days
val days = ChronoUnit.DAYS.between(LocalDate.now(), futureDate)
// print the result
println("$days days left")
}
Output (again):
110 days left
Try below code -
val previousTimeDouble: Double = previousTime.toDouble()
val nowTimeDouble: Double = System.currentTimeMillis().toDouble()
val dateNowString: String = dateNow.toString();
val time: Long = (nowTimeDouble - previousTimeDouble).toLong()
val difference: String= differenceBetweenTwoTimes(time)
Log.d("difference", difference)
Function for converting time difference into units -
fun differenceBetweenTwoTimes(time: Long): String {
var x: Long = time / 1000
var seconds = x % 60
x /= 60
var minutes = x % 60
x /= 60
var hours = (x % 24).toInt()
x /= 24
var days = x
return String.format("%02d:%02d:%02d", hours, minutes, seconds)
}

How do I initialize these arrays?

I want to have a class that stores three sets of 30 Foos each. I can declare them as arrays of Foo but I don't know how I can initialize them (give them default values) with 30 elements.
data class Container (
val first: Array<Foo>,
val second: Array<Foo>,
val third: Array<Foo>,
)
data class Foo (val a: Int, val b: Int)
There aren't too many ways to create an array in Kotlin and they are pretty straightforward. Depending on your needs, you can either use arrayOf() function, Array() constructor or create List first and then convert it into array.
Example with arrayOf():
val first = arrayOf(
Foo(0, 0),
Foo(1, 1),
...
)
Array():
val first = Array(30) { Foo(it, it) }
List:
val firstList = mutableListOf<Foo>()
firstList += Foo(0, 0)
firstList += Foo(1, 1)
...
first = firstList.toTypedArray()
If the code for generating these arrays is complicated, you can write it inside init {} block or create static function(s) that provides these arrays.

Kotlin: Get Values of a Range in another Range

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)

Format a number to string, fill 0 when it's not enough two characters

I want to format the number to String and fill 0 when it's not enough two characters
fun formatDuration(val duration):String {
val minutes = duration.toInt() / 60
return "$minutes"
}
For example, if minutes is 6, it should displayed 06 rather than 6.
You can padStart the toString() result of minutes.
I tried your code in the Kotlin Playground and it wasn't compilable / runnable. For the following example, I had to change parts of your fun:
fun main() {
println(formatDuration(364.34))
}
fun formatDuration(duration: Double): String {
val minutes = duration.toInt() / 60
// fill the result to be of 2 characters, use 0 as padding char
return minutes.toString().padStart(2, '0')
}
Executing this results in the output 06.
Alternatively, you can simply use String.format() from Java, just
return "%02d".format(minutes)
instead of return minutes.toString().padStart(2, '0'), the result stays the same.
You can achive this with padStart
Example:
val padWithSpace = "125".padStart(5)
println("'$padWithSpace'") // ' 125'
val padWithChar = "a".padStart(5, '.')
println("'$padWithChar'") // '....a'
// string is returned as is, when its length is greater than the specified
val noPadding = "abcde".padStart(3)
println("'$noPadding'") // 'abcde'

How to create variables in a for-loop with Kotlin

Given a maximum list size in parameter size and total amount of elements in parameter elements, I need to create a list of lists. What is the syntax for creating variables in for loops in Kotlin?
The way I'm thinking of going about this is to declare and create lists before elements are added to a list. Then, when a list has reached full capacity, it is switched out for the next list that is empty.
Here is the half-baked code:
fun listOfLists(size: Int, vararg elements: String): List<List<String>> {
var amountOfElements = elements.size
var currentSubList: List<String> = mutableListOf<String>()
val numberOfLists: Int = amountOfElements / size + 1
for (n in 0..numberOfLists) {
// Code for creating the total number of lists needed
}
for (e in elements) {
if (amountOfElements % size == 0) {
// Code for switching lists
}
amountOfElements--
}
As #dyukha correctly mentioned, what you need is chunked() function.
fun listOfLists(size: Int, vararg elements: String) =
elements.asList().chunked(size)
Or, if you want to be really efficient, you can also use asSequence():
fun listOfLists(size: Int, vararg elements: String) =
elements.asSequence().chunked(size)
chunked() doesn't work on Array, because it's defined on Iterable and Sequence, and Array doesn't implement any of them.