Update random class attribute in Kotlin - kotlin

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)

Related

Merge properties of a list to another based on properties objects

I got 2 lists with x objects inside , for example:
data class Model(
var token: String = "",
var id: String = "",
var name: String = "",
var image: Int = 0,
)
array is initialized and filled, the other list has x objects also that contains the objects of the first list but with different values in their properties!
what I want to do is to change the properties of the first array by the second one if they got the same object.name
var arr1 = ArrayList<Model>() // locale
var arr2 = ArrayList<Model>() // from db
the first array I got for example
[Model(name = "David", token = "" , image = 0)]
the second array I got
[Model(name = "David", token = "1asd5asdd851", image = 1)]
How do I make the first array take the missing token?
I tried with .filter{} and with .map{}. groupBy {} for hours because Name is the only properties that are the same but I'm more and more confused.
We can first group the second array by name using associateBy() and then iterate over first array and reassign properties:
val arr2ByName = arr2.associateBy { it.name }
arr1.forEach { item1 ->
arr2ByName[item1.name]?.let { item2 ->
item1.token = item2.token
item1.image = item2.image
}
}
Alternatively, if you don't need to modify items in arr1, but create another array and you can use items from both arr1 and arr2, then it will be much easier:
val arr3 = arr1.map { arr2ByName[it.name] ?: it }
One possible way would be to use fold() as follows:
fun main(args: Array<String>) {
val arr1 = listOf(Model(name = "David", token = "" , image = 0))
val arr2 = listOf(Model(name = "David", token = "1asd5asdd851", image = 1))
val mergedModels = arr2.fold(arr1) { localModels, dbModel ->
localModels.map { localModel ->
if (localModel.name == dbModel.name) localModel.copy(token = dbModel.token, image = dbModel.image)
else localModel
}
}
println(mergedModels)
}
If you want to reuse arr1 variable then you can do the following (but I would still use the previous option):
fun main(args: Array<String>) {
var arr1 = listOf(Model(name = "David", token = "" , image = 0))
val arr2 = listOf(Model(name = "David", token = "1asd5asdd851", image = 1))
arr1 = arr2.fold(arr1) { localModels, dbModel ->
localModels.map { localModel ->
if (localModel.name == dbModel.name) localModel.copy(token = dbModel.token, image = dbModel.image)
else localModel
}
}
println(arr1)
}

How to use the spread operator with ArrayList in kotlin?

I've read the documentation and I run into this issue of using the spread operator with an ArrayList Collection, and I want to know how to solve the mismatch type or implement a way to use it with ArrayList
I'll attach an image of the code along with the code.
fun howSum(targetSum: Int, numbers: ArrayList<Int>): ArrayList<Int>? {
if (targetSum == 0) return arrayListOf();
if (targetSum < 0) return null;
for (number: Int in numbers){
val remainder = targetSum - number;
val remainderResult = howSum(remainder, numbers);
if (remainderResult != null){
return arrayListOf(*remainderResult, number)
}
}
return null
}
Any comment could be helpful...
I think you need to give us more information about what you are trying to do for a better answer.
The spread operator is for passing an array in place of a varargs argument, but you can't add additional arguments to the array at the same time.
If you want a new ArrayList that contains the contents of another ArrayList with an extra element added, you can do something like this:
fun main() {
val foo = arrayListOf(1, 2, 3)
val bar = arrayListOf<Int>().apply {
addAll(foo)
add(4)
}
println(foo)
println(bar)
}
Output:
[1, 2, 3]
[1, 2, 3, 4]
But it's not efficient, because it copies all the items of foo into bar.
Spread operator is not applicable to Lists, it's intended only for arrays:
fun howSum(targetSum: Int, numbers: ArrayList<Int>): IntArray? {
if (targetSum == 0) return intArrayOf()
if (targetSum < 0) return null
for (number: Int in numbers) {
val remainder = targetSum - number;
val remainderResult = howSum(remainder, numbers);
if (remainderResult != null) {
return intArrayOf(*remainderResult, number)
}
}
return null
}
If you want to create new List of the other one with addition of some element, you can use + operator:
fun howSum(targetSum: Int, numbers: ArrayList<Int>): List<Int>? {
if (targetSum == 0) return arrayListOf();
if (targetSum < 0) return null;
for (number: Int in numbers){
val remainder = targetSum - number;
val remainderResult = howSum(remainder, numbers);
if (remainderResult != null){
return remainderResult + number
}
}
return null
}

Reference Equality in Kotlin

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

Kotlin - The caracter literal does not conform expect type Int

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(""))

Assigning values to ArrayList using mapTo

Previously I was using this code:
private val mItems = ArrayList<Int>()
(1..item_count).mapTo(mItems) { it }
/*
mItems will be: "1, 2, 3, 4, 5, ..., item_count"
*/
Now, I am using a class instead of Int, but the class has Int member with name id.
class ModelClass(var id: Int = 0, var status: String = "smth")
So how can I use this method to fill the ArrayList in similar way?
//?
private val mItems = ArrayList<ModelClass>()
(1..item_count).mapTo(mItems) { mItems[position].id = it } // Something like this
//?
From the mapTo documentation:
Applies the given transform function to each element of the original collection and appends the results to the given destination.
Therefore, you just need to return the elements you want:
(1..item_count).mapTo(mItems) { ModelClass(it) }
If you are OK with any MutableList (which is often ArrayList or similar):
val mItems1 = MutableList(item_count) { i -> i }
val mItems2 = MutableList(item_count) { ModelClass(it) }