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
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
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()
}
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:
- Type argument of
PriorityQueue
should be aProduct
(if you want to store these objects in it). - Lambda of
Comparator
should returnInt
, notLong?
. If it's guaranteed, that there will be noProduct
s withpriceInLong == 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 }