Home > front end >  Order ArrayList with Int and String in Kotlin
Order ArrayList with Int and String in Kotlin

Time:04-29

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())
  • Related