I have the given array
val things = arrayOf<Any>("Jack", 8, 2, 6, "King", 5, 3, "Queen", "Jack");
Below is the code I have used
things.set(things.indexOf("Jack"), 11);
things.set(things.indexOf("Queen"), 12);
things.set(things.indexOf("King"), 13);
things.sort();
things.set(things.indexOf(11), "Jack"));
things.set(things.indexOf(12), "Queen");
things.set(things.indexOf(13), "King");
things.joinToString(":");
things.forEach { System.out.print(it) }
Here is the error I keep getting
Unexpected tokens (use ';' to separate expressions on the same line)
Expecting an element
After removing the trailing bracket, I now get the following error
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String (java.lang.Integer and java.lang.String are in module java.base of loader 'bootstrap')
at java.lang.String.compareTo (:-1)
at java.util.ComparableTimSort.binarySort (:-1)
at java.util.ComparableTimSort.sort (:-1)
CodePudding user response:
You've 2 Jack
in your list, so when you use indexOf()
, it returns the index of the first occurrence of that item.
things.set(things.indexOf("Jack"), 11);
things.set(things.indexOf("Queen"), 12);
things.set(things.indexOf("King"), 13);
This changes your list to
[11, 8, 2, 6, 13, 5, 3, 12, Jack]
Now, when you apply the sort()
operation on things
. It throws ClassCastException
on Jack
as it's a string
, not an int
.
To find all the indexes
of a value, so you can replace them, you can create an extension
function that returns a list of all the indices for a value.
fun <T> Array<T>.indexesOfAll(predicate: (T) -> Boolean): List<Int> {
return mapIndexedNotNull { index, any ->
index.takeIf {
predicate(any)
}
}
}
Now, you can use this indexesOfAll
function to get the indexes
of all the items for a particular condition.
things.indexesOfAll { it == "Jack" }.forEach {
things.set(it, 11)
}
You can do the same for all other values too.
CodePudding user response:
the problem is that you have "Jack" two times in it. things.set(things.indexOf("Jack"), 11);
only changes the first one to 11, not the second one.
val things = arrayOf<Any>("Jack", 8, 2, 6, "King", 5, 3, "Queen", "Jack");
things.set(things.indexOf("Jack"), 11);
things.set(things.indexOf("Queen"), 12);
things.set(things.indexOf("King"), 13);
println(things.contentToString()) //prints [11, 8, 2, 6, 13, 5, 3, 12, Jack]
Now, how I maybe would do it, is like this:
fun main() {
val things = arrayOf("Jack", 8, 2, 6, "King", 5, 3, "Queen", "Jack")
things.sortWith(compareBy { it.toInt() })
println(things.contentToString()) //prints [2, 3, 5, 6, 8, Jack, Jack, Queen, King]
}
val mapping = mapOf("Jack" to 11, "Queen" to 12, "King" to 13)
fun Any.toInt() : Int {
if (this is Int) return this
return mapping[this] ?: 0
}
CodePudding user response:
Even though the other answers solve the problem at hand, there is a base issue at play. Normally you would want to avoid having multi-typed arrays (or any type of collection).
A better solution would be to introduce and abstraction to represent both types of data as the same class and make that class implement the Comparable
interface.
An implementation example of this:
sealed class Card(val name: String) : Comparable<Card> {
abstract val order: Int
override fun compareTo(other: Card): Int =
order - other.order
override fun toString(): String = name
class Number(value: Int) : Card(value.toString()) {
override val order: Int = value
}
object Ace : Card("Ace") {
override val order: Int = 1
}
object Jack : Card("Jack") {
override val order: Int = 11
}
object Queen : Card("Queen") {
override val order: Int = 12
}
object King : Card("King") {
override val order: Int = 13
}
}
then you could use it like this:
println(listOf(Card.Number(2), Card.Ace, Card.Queen, Card.Number(3)).sorted())