Home > Mobile >  How to use comparator in priority queue kotlin
How to use comparator in priority queue kotlin

Time:02-23

Hey I want to use custom comparator in priority queue in kotlin. I have data class

Product.kt

data class Product(val value: String? = null, val price: String? = null) {
    var priceInLong = price?.toLong()
}

I want to create a min heap where price value will be minimum. I am creating the object but it giving me some kind of error

fun main() {
    var queue = PriorityQueue<Long> { p1: Product, p2: Product ->
        p1.priceInLong?.let {
            p2.priceInLong?.minus(it)
        }
    }

    val list = listOf(
        Product("1", "4.83"),
        Product("2", "4.53"),
        Product("3", "3.54"),
        Product("4", "3.66"),
        Product("5", "5.16")
    )
}

error

None of the following functions can be called with the arguments supplied.
<init>((MutableCollection<out TypeVariable(E)!>..Collection<TypeVariable(E)!>?))   where E = TypeVariable(E) for    constructor PriorityQueue<E : Any!>(c: (MutableCollection<out E!>..Collection<E!>?)) defined in java.util.PriorityQueue
<init>(Comparator<in TypeVariable(E)!>!)   where E = TypeVariable(E) for    constructor PriorityQueue<E : Any!>(comparator: Comparator<in E!>!) defined in java.util.PriorityQueue
<init>(PriorityQueue<out TypeVariable(E)!>!)   where E = TypeVariable(E) for    constructor PriorityQueue<E : Any!>(c: PriorityQueue<out E!>!) defined in java.util.PriorityQueue
<init>(SortedSet<out TypeVariable(E)!>!)   where E = TypeVariable(E) for    constructor PriorityQueue<E : Any!>(c: SortedSet<out E!>!) defined in java.util.PriorityQueue
<init>(Int)   where E = TypeVariable(E) for    constructor PriorityQueue<E : Any!>(initialCapacity: Int) defined in java.util.PriorityQueue

image

enter image description here

1. I want to solve this error and add value by price which is minimum comes first.

2. Is my above queue comparator logic is correct to use min heap?

Thankss

UPDATE

I tried this suggestion

var queue = PriorityQueue<Product> { p1, p2 ->
        return if (p1.priceInLong != null && p2.priceInLong != null) {
            p2.priceInLong - p1.priceInLong
        } else {
            0
        }
    }

getting error

enter image description here

UPDATE 2

val queue = PriorityQueue<Product> { p1, p2 ->
        val priceOne = p1.priceInLong
        val priceTwo = p2.priceInLong
        if (priceOne != null && priceTwo != null) {
            if(priceOne == priceTwo){
                return 0 
            }
        } else {
            return 0
        }
    }

data class Product(val value: String? = null, val price: String? = null) {
    val priceInLong = price?.toLong()
}

enter image description here

CodePudding user response:

This:

{ p1: Product, p2: Product ->
        p1.priceInLong?.let {
            p2.priceInLong?.minus(it)
        }
}

returns null if p1.priceInLong is null (the let block isn't executed), or if p2.priceInLong is null (the let block returns null). That's what the null-safety checking with ? does.

You're getting the error because your Comparator function needs to return an Int, but yours returns Int?, i.e. a nullable int value - could be an int, could be null. So it doesn't match the required constructor, that's why it's complaining that none of the functions match.

So you need to decide what to do if one (or both) of those values are null, and return an integer instead of any nulls, so your function returns Int and not Int?


If what you're saying in the comments is correct, and neither of those values will ever be null, you can just assert that with !!

{ p1: Product, p2: Product ->
    p2.priceInLong!! - p1.priceInLong!!
}

But using !! is a bad sign - how do you know they'll never be null? If you can say that for sure, why is priceInLong nullable in the first place?

CodePudding user response:

I want to solve this error

Two problems here:

  1. Type argument of PriorityQueue should be a Product (if you want to store these objects in it).
  2. Lambda of Comparator should return Int, not Long?. If it's guaranteed, that there will be no Products with priceInLong == null, you may just use the not-null assertion operator to get rid of nullability and then get sign of difference to avoid possible integer overflow of .toInt() conversion:
val queue = PriorityQueue<Product> { p1, p2 -> (p1.priceInLong!! - p2.priceInLong!!).sign }
  • Related