I'm learning Kotlin, in the tutorial example:
fun main() {
val a: Int = 100
val boxedA: Int? = a
val anotherBoxedA: Int? = a
val b: Int = 1000
val boxedB: Int? = b
val anotherBoxedB: Int? = b
println(boxedA === anotherBoxedA) // true
println(boxedB === anotherBoxedB) // false
}
Why is the result of two comparision different?
Most likely because of the JDK implementation of Integer.valueOf
https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#valueOf(int)
Returns an Integer instance representing the specified int value. If a new Integer instance is not required, this method should generally be used in preference to the constructor Integer(int), as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
If you decompile the method in Intellij, you'll find
public static final void main() {
int a = 100;
Integer boxedA = Integer.valueOf(a);
Integer anotherBoxedA = Integer.valueOf(a);
int b = 1000;
Integer boxedB = Integer.valueOf(b);
Integer anotherBoxedB = Integer.valueOf(b);
boolean var6 = boxedA == anotherBoxedA;
boolean var7 = false;
System.out.println(var6);
var6 = boxedB == anotherBoxedB;
var7 = false;
System.out.println(var6);
}
Related
In Java you have:
byte[] bytes = ...
int pos = ...
int length = ...
new String(bytes, pos, length)
This will create one additional byte[] internally in String.
What is the most efficient way to do that in Kotlin (i.e. with the least amount of additional objects)?
val bytes : ByteArray = ...
val pos : Int = ...
val length : Int = ...
???
val bytes: ByteArray = ByteArray(10) { ('a'..'z').toList()[it].code.toByte() }
val pos: Int = 3
val length: Int = 4
val result = String(bytes.sliceArray(pos until pos + length))
I have a class with some attributes:
class DonutBox {
var glaze: Int = 0
var chocolate: Int = 0
var maple: Int = 0
var etc: Int = 0
}
fun addDonuts() {
val omNom = DonutBox()
}
How can I increment a random attribute of the instantiated class?
For instance, if the randomly selected attribute is chocolate, then effectively:
omNom.chocolate += 1
Because Kotlin's properties are statically declared, and you want to use them dynamically, most of the methods to do that will involve reflection, which can get pretty messy and difficult to understand.
When you want dynamic data, it's probably better to use a map:
val donutBox = mutableMapOf(
"glaze" to 0,
"chocolate" to 0,
"maple" to 0,
"etc" to 0,
)
val randomKey = donutBox.keys.random()
donutBox[randomKey] = donutBox.getValue(randomKey) + 1
println(donutBox)
Output:
{glaze=0, chocolate=0, maple=1, etc=0}
That said, if you really want to use reflection, you can do it like this:
data class DonutBox(
var glaze: Int = 0,
var chocolate: Int = 0,
var maple: Int = 0,
var etc: Int = 0,
)
fun addDonuts() {
val omNom = DonutBox()
val randomProperty = omNom::class.declaredMemberProperties.random() as KMutableProperty1<DonutBox, Int>
val existing = randomProperty.get(omNom)
randomProperty.set(omNom, existing + 1)
println(omNom)
}
fun main() {
addDonuts()
addDonuts()
addDonuts()
}
Output:
DonutBox(glaze=0, chocolate=1, maple=0, etc=0)
DonutBox(glaze=0, chocolate=0, maple=0, etc=1)
DonutBox(glaze=0, chocolate=1, maple=0, etc=0)
I'm struggling with types with my program, I've been asked to do it in JS first and it worked fine but now I can't achieve the result.
Do you think I should make another 'algorithm' ? In advance, thank you for your time.
fun main(){
// the idea is to put numbers in a box
// that cant be larger than 10
val data = "12493419133"
var result = data[0]
var currentBox = Character.getNumericValue(data[0])
var i = 1
while(i < data.length){
val currentArticle = Character.getNumericValue(data[i])
currentBox += currentArticle
println(currentBox)
if(currentBox <= 10){
result += Character.getNumericValue(currentArticle)
}else{
result += '/'
//var resultChar = result.toChar()
// result += '/'
currentBox = Character.getNumericValue(currentArticle)
result += currentArticle
}
i++
}
print(result) //should print 124/9/341/91/33
}
The result is actually of a Char type, and the overload operator function + only accepts Int to increment ASCII value to get new Char.
public operator fun plus(other: Int): Char
In idomatic Kotlin way, you can solve your problem:
fun main() {
val data = "12493419133"
var counter = 0
val result = data.asSequence()
.map(Character::getNumericValue)
.map { c ->
counter += c
if (counter <= 10) c.toString() else "/$c".also{ counter = c }
}
.joinToString("") // terminal operation, will trigger the map functions
println(result)
}
Edit: If the data is too large, you may want to use StringBuilder because it doesn't create string every single time the character is iterated, and instead of using a counter of yourself you can use list.fold()
fun main() {
val data = "12493419133"
val sb = StringBuilder()
data.fold(0) { acc, c ->
val num = Character.getNumericValue(c)
val count = num + acc
val ret = if (count > 10) num.also { sb.append('/') } else count
ret.also { sb.append(c) } // `ret` returned to ^fold, next time will be passed as acc
}
println(sb.toString())
}
If you want a result in List<Char> type:
val data = "12493419133"
val result = mutableListOf<Char>()
var sum = 0
data.asSequence().forEach {
val v = Character.getNumericValue(it)
sum += v
if (sum > 10) {
result.add('/')
sum = v
}
result.add(it)
}
println(result.joinToString(""))
I'm attempting to compare different run-times for simple blocks of code, but continue to get 0 returned. What can I do to get a better approximation for the execution time?
private var trackConstantTime: Long? = null
this.trackConstantTime = measureTimeMillis {
/* determine if a given number is even or odd */
var n = (0..(Int.MAX_VALUE)).random()
if(n % 2 == 0) "Even" else "Odd"
}
println("O(1), Constant Time for fxConstantTime(...):${TimeUnit.MILLISECONDS.toSeconds(trackConstantTime!!)}")
Similarly if I'll attach another example that's returning 0 for the runtime.
private var trackLinearTime: Long? = null
private var uL: MutableList<Int> = mutableListOf()
for(i in 0..100){
this.uL.add( ((0)..(100)).random() )
}
this.trackLinearTime = measureTimeMillis {
/* determine the maximum value in an unsorted array */
var max: Int = 0
for(i in 0 until uL.size) {
if (uL[i] > max) max = uL[i]
println(max)
}
}
println("O(n), Linear Time for fxLinearTime(...):${TimeUnit.MILLISECONDS.toSeconds(trackLinearTime!!)}")
Maybe try to measure time in nanoseconds:
this.trackLinearTime = measureNanoTime {
...
}
I'm porting a class called ShapeData from Java which is filled with nullable types. It looks like this:
class ShapeData {
var type: Shape.Type? = null // Circle, Edge, Polygon, Chain
// PolygonShape / ChainShape
var vertices: FloatArray? = null
var offset: Int? = null
var len: Int? = null
// setAsBox
var hx: Float? = null
var hy: Float? = null
var center: Vector2? = null
var angle: Int? = null
// CircleShape
var radius: Float? = null
var position: Vector2? = null
// EdgeShape
var v1: Vector2? = null
var v2: Vector2? = null
}
These properties are nullable because they are read from JSON and might not exist, and since certain fields allow negative values -1 is not a valid default.
Certain properties need to be scaled if they exist so for that I'm converting a previously static method to a Kotlin top-level function, however I've run into a bit of an issue:
fun scaledShapeData(data: ShapeData, scalar: Float): ShapeData {
return ShapeData().apply {
type = data.type
vertices = data.vertices?.map { it * scalar }?.toFloatArray()
offset = data.offset
len = data.len
hx = if(data.hx != null) data.hx * scalar else null // This is marked as an error with "None of the following functions can be called with the arguments supplied" message
}
}
The precise message i get is this (image since Android Studio doesn't let me select and copy the message):
I've also tried to replicate this in the Kotlin playground with this piece of code:
fun main(args: Array<String>) {
var test1 : Float? = 2f
val test2 : Float = 2f
var test3 : Float? = if(test1 != null) test1 * test2 else null
print(test3)
}
And this compiles and outputs 4.0 as expected. As far as I can see the two code samples are near identical.
What exactly am I doing wrong and how can I fix this?
// This is marked as an error with "None of the following functions can be called with the arguments supplied" message
hx = if(data.hx != null) data.hx * scalar else null
The difference between your playground example and this example is that data.hx may change between the null check and the multiplication.
You can use the following instead, using the times function on Int:
hx = hdata.hx?.times(scalar)
since * is translated to times.