Ranges in Kotlin - kotlin

How do I write code to return a range of 10 numbers from a given number.
i.e if I am given 5, code should return 0..9
358 should return 350..359
33 should return 30..39 etc

Do you mean something like this?
fun range10(contained: Int): IntRange {
val start = contained - contained % 10
val end = start + 9
return start..end
}

If the given number is integer type, you can simply write
val x = 358
(x / 10 * 10)..(x / 10 * 10 + 9)

You can use the following code:
fun answer(givenNum: Int) : IntRange {
val startOfRange = givenNum - (givenNum % 10)
return startOfRange until (startOfRange + 10)
}
fun main() {
val givenNum = 33
println(answer(givenNum)) // 30..39
}

Related

Kotlin Integer.MAX_VALUE Returns Negative Number

Expected
Use Integer.MAX_VALUE in order to consistently return a large number for the purposes of comparison.
Observed
Integer.MAX_VALUE is returning a negative number.
Implement
In the sample code values are saved into a 2D table in order to find the minimum amount of coins required to make up a given amount.
Using Integer.MAX_VALUE
-2147483647 is being derived from Integer.MAX_VALUE.
fun main() {
// Steps - Iterative/bottom-up
// 1. Create a 2D table: Rows = Denominations(Denoms), Columns = Amount(Amt)
// 2. Store min # of coins in at [R][C] = Min(currentDenomMin, previousDenomMin)
// a. currentDenomMin = [R][C - coins.get(R)] + 1
// b. previousDenomMin = [R - 1][C]
// 3. Return minCount or -1 for table[coins.size - 1, Amt].
println("Min count: ${coinChange(intArrayOf(2), 3)}")
}
lateinit var table: Array<IntArray>
lateinit var mCoins: IntArray
private val maxValue = Integer.MAX_VALUE
fun coinChange(coins: IntArray, amt: Int): Int {
table = Array(coins.size, { IntArray(amt + 1) })
mCoins = coins
coins.sort()
buildMinCounts(amt)
val minCount = table[coins.size - 1][amt]
return if (minCount == maxValue) -1 else minCount
}
fun buildMinCounts(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
val currentDenomValue = mCoins.get(r)
val currentDenomMin = getDenomMin(r, c - currentDenomValue) + 1
val previousDenomMin = getDenomMin(r - 1, c)
if (c == 0) {
table[r][c] = 0
} else table[r][c] = Math.min(currentDenomMin, previousDenomMin)
}
}
}
fun getDenomMin(r: Int, c: Int): Int {
if (r < 0 || c < 0) return maxValue
else return table[r][c]
}
fun printT(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
print("${table[r][c]} ")
}
println("")
}
}
Using 999999999 as the maxValue instead
Works as expected.
fun main() {
println("Min count: ${coinChange(intArrayOf(2), 3)}")
}
lateinit var table: Array<IntArray>
lateinit var mCoins: IntArray
private val maxValue = 999999999
fun coinChange(coins: IntArray, amt: Int): Int {
table = Array(coins.size, { IntArray(amt + 1) })
mCoins = coins
coins.sort()
buildMinCounts(amt)
val minCount = table[coins.size - 1][amt]
return if (minCount == maxValue) -1 else minCount
}
fun buildMinCounts(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
val currentDenomValue = mCoins.get(r)
val currentDenomMin = getDenomMin(r, c - currentDenomValue) + 1
val previousDenomMin = getDenomMin(r - 1, c)
if (c == 0) {
table[r][c] = 0
} else table[r][c] = Math.min(currentDenomMin, previousDenomMin)
}
}
}
fun getDenomMin(r: Int, c: Int): Int {
if (r < 0 || c < 0) return maxValue
else return table[r][c]
}
fun printT(amt: Int) {
for (r in 0..mCoins.size - 1) {
for (c in 0..amt) {
print("${table[r][c]} ")
}
println("")
}
}
It's because of overflow. getDenomMin(r, c - currentDenomValue) + 1 returns Integer.MAX_VALUE + 1 which causes overflow. There are two ways to avoid this:
Change maxValue to something such that it doesn't overflows and is actually is the maximum. For example, you have array of size 10^5 containing integers between 1 and 10^9. Now maximum possible sum will 10^5 * 10^9 which is 10^14 so we can set maxValue to any value greater than or equal to 10^14. In your case you can set it to something like 10^5 because you need count not sum which can be at max number of coins available.
val currentDenomMin = getDenomMin(r, c - currentDenomValue) + 1 Before adding 1 you can type it to Long so that it doesn't overflow.
val currentDenomMin = getDenomMin(r, c - currentDenomValue).toLong + 1

Kotlin: Dynamically choose companion object function

My Enum class and companion object are as follows:
enum class Temperature(val names: List<String>) {
Celsius(listOf("degree Celsius", "degrees Celsius", "celsius", "dc", "c")),
Kelvin(listOf("Kelvin", "Kelvins", "k")),
Fahrenheit(listOf("degree Fahrenheit", "degrees Fahrenheit", "fahrenheit", "df", "f"));
companion object Conversion {
fun CelsiusToKelvin(c: Double) = c + 273.15
fun CelsiusToFahrenheit(c: Double) = (c * 9 / 5) + 32
fun FahrenheitToKelvin(f: Double) = (f + 459.67) * 5 / 9
fun FahrenheitToCelsius(f: Double) = (f - 32) * 5 / 9
fun KelvinToCelsius(K: Double) = K - 273.15
fun KelvinToFahrenheit(K: Double) = K * 9 / 5 - 459.67
}
}
I get input temperature in a scale which I need to convert to a different output scale. Is there a way to dynamically call the companion object functions based on the input and output scales?
For example:
var convert = "CelsiusToKelvin"
val value = 36.9
val myFunc = Temperature.getFunction(convert)
val myOutput = myFunc(value)
This should invoke the Temperature.CelsiusToKelvin function.
I know that I can check the input using if or when statements and manually invoke the function I want. But is it possible without doing this?
Edit 1:
I solved it using when by changing the function:
companion object Conversion {
fun convert(a:String,b:String,c:Double) = when {
a == "Celsius" && b == "Kelvin" -> c + 273.15
a == "Celsius" && b == "Fahrenheit" -> (c * 9 / 5) + 32
a == "Fahrenheit" && b == "Kelvin" -> (c + 459.67) * 5 / 9
a == "Fahrenheit" && b == "Celsius" -> (c - 32) * 5 / 9
a == "Kelvin" && b == "Celsius" -> c - 273.15
a == "Kelvin" && b == "Fahrenheit" -> c * 9 / 5 - 459.67
else -> 0.0
}
}
But I want to know if what I originally wanted to do was possible
I think a better approach, if you must use Strings, is to dynamically determine the constant, and have each constant provide the necessary conversion functions. For example:
// Note: Didn't include your "names" property
enum class Temperature {
Celsius {
override fun toKelvin(value: Double) = value + 273.15
override fun toFahrenheit(value: Double) = (value * 9.0 / 5.0) + 32.0
},
Kelvin {
override fun toCelsius(value: Double) = value - 273.15
override fun toFahrenheit(value: Double) = value * 9.0 / 5.0 - 459.67
},
Fahrenheit {
override fun toCelsius(value: Double) = (value - 32.0) * 5.0 / 9.0
override fun toKelvin(value: Double) = (value + 459.67) * 5.0 / 9.0
};
open fun toCelsius(value: Double) = value
open fun toKelvin(value: Double) = value
open fun toFahrenheit(value: Double) = value
fun convert(value: Double, target: Temperature) = when (target) {
Celsius -> toCelsius(value)
Kelvin -> toKelvin(value)
Fahrenheit -> toFahrenheit(value)
}
companion object {
fun convert(source: String, target: String, value: Double) =
valueOf(source).convert(value, valueOf(target))
}
}
The valueOf method, which is added implicitly by the compiler, will throw an IllegalArgumentException if the string does not match the name of an enum constant exactly. Your code has a similar requirement except you return 0 if there's no match. I personally prefer the exception.

repeat string n times in Kotlin

I want to create a string which would contain a * symbol n times.
I only see this way:
val s = ""
val n = 100
for (j in 0 until n) {
s += "*"
}
But it looks ugly and it has a O(n^2) time complexity. Is there a way in Kotlin to do that without a loop with better time complexity?
The built in CharSequence.repeat extension does this in an efficient way, see the source here.
val str: String = "*".repeat(100)
Of course, this will still require O(n) steps to create the string. However, using this built-in stdlib function has its advantages: it's cross-platform, easy to read, and can be improved in performance over time, if there's a more efficient solution. The loop inside it will probably be optimized by the compiler or the runtime anyway.
You can overload the * operator to map it to the existing repeat extension:
public operator fun CharSequence.times(count: Int): String {
return repeat(count)
}
fun main() {
val s = "*" * 101
println(s)
println("Badger " * 12 + "Mushroom " * 2)
println(s)
}
An alternative to the CharSequence.repeat is a CharArray with an init function:
CharArray(N, {i -> '*'}).joinToString(separator="")
This solution has the advantage that you can define prefix, postfix, and separator.
StringBuilder would improve the memory footprint here:
val sb = StringBuilder()
val n = 100
for (j in 0 until n) {
sb.append("*")
}
If you need a separator, this initializer function from List is helpful:
val str: String = List(100) { "*" }.joinToString(",")
Thanks to Anton Sizikov and https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/repeat.html, we can write:
val sb = StringBuilder().apply{
repeat(100) {
append("*")
}
}
But this is a simple way. Look at a power function. It has O(log n) complexity.
For StringBuilder:
private fun power(sb: StringBuilder, n: Int): StringBuilder =
when {
n == 0 -> StringBuilder("")
n % 2 == 0 -> {
val part = power(sb, n / 2)
part.append(part)
}
else -> {
val part = power(sb, n / 2)
part.append(part).append(sb)
}
}
For String:
private fun pow(s: String, n: Int): String =
when {
n == 0 -> ""
n % 2 == 0 -> pow(s, n / 2).repeat(2)
else -> s + pow(s, n / 2).repeat(2)
}
Then we can invoke them:
// 1.
val sb1 = StringBuilder().apply {
repeat(100) {
append("*")
}
}
// 2.
val sb2 = power(StringBuilder("*"), 100)
// 3.
val s = power("*", 100)
println(sb1.toString())
println(s)
println(sb2.toString())

Loop String from Console and sum odd numbers

fun main(args: Array<String>) {
println("Number: ")
val num = readLine()!!.toInt()
var sum = 0
for (digit in num) {
if (digit % 2 != 0) {
sum += digit
}
}
println("$sum")
}
I need this loop to go through every digit in the number and sums all the digits that are odd.
It gives me an error on num "For-loop range must have an 'iterator()' method"
You cannot iterate over an Int like num:
val num = readLine()!!.toInt()
You can fix it without a loop and by using standard functions map, filter and sum:
val sum = readLine()!!.toCharArray()
.map { it.toString().toInt() }
.filter { it % 2 != 0 }
.sum()
The filter-condition for even numbers would be it % 2 == 0
EDIT
For your homework, do this:
val num = readLine()!!.toCharArray()
var sum = 0
for (a in num) {
val intVal = a.toString().toInt()
if (intVal % 2 != 0) {
sum += intVal
}
}

Sum a subset of of numbers in a list

Is there a way in Kotlin for doing the sum() operation on a filtered list of numbers, without actually filtering out the elements first?
I'm looking for something like this:
val nums = listOf<Long>(-2, -1, 1, 2, 3, 4)
val sum = nums.sum(it > 0)
You can make use of Iterable<T>.sumBy:
/**
* Returns the sum of all values produced by [selector] function applied to each element in the collection.
*/
public inline fun <T> Iterable<T>.sumBy(selector: (T) -> Int): Int {
var sum: Int = 0
for (element in this) {
sum += selector(element)
}
return sum
}
You can pass a function to it where the function transforms negative value to 0. So, it sums up all values in the list which is greater than 0 since adding 0 makes no effect to the result.
val nums = listOf<Long>(-2, -1, 1, 2, 3, 4)
val sum = nums.sumBy { if (it > 0) it.toInt() else 0 }
println(sum) //10
If you require a Long value back, you have to write an extension for Long just like Iterable<T>.sumByDouble.
inline fun <T> Iterable<T>.sumByLong(selector: (T) -> Long): Long {
var sum: Long = 0
for (element in this) {
sum += selector(element)
}
return sum
}
Then, the toInt() conversion can be taken away.
nums.sumByLong { if (it > 0) it else 0 }
As suggested by #Ruckus T-Boom, if (it > 0) it else 0 can be simplified using Long.coerceAtLeast() which returns the value itself or the given minimum value:
nums.sumByLong { it.coerceAtLeast(0) }
sumBy and sumByDouble are Deprecated from kotlin 1.5 . You can check those link.
Use sumOf to get sum on a List or Array
sumOf
Returns the sum of all values produced by selector function applied to each element in the collection or Array.
Example:
data class Order(
val id : String,
val price : Double
)
val orderList = ......
val sum = orderList.sumOf { it.price }
data class Product(val name: String, val quantity: Int) {
}
fun main(args: Array<String>) {
val productList = listOf(
Product("A", 100),
Product("B", 200),
Product("C", 300)
)
val totalPriceInList1: Int = productList.map { it.quantity }.sum()
println("sum(): " + totalPriceInList1)
val totalPriceInList2: Int = productList.sumBy { it.quantity }
println("sumBy(): " + totalPriceInList2)
}
this is the result of our code
sum(): 600
sumBy(): 600