Unable to invoke no-args constructor for class ConversionRates - api

I have a Currency Converter Android app. I 'm using retrofit for getting rates from API but as far as I'm concerned my app can't get data from api and it returns that exception
Unable to invoke no-args constructor for class package name.ConversionRates. Registering an InstanceCreator with Gson for this type may fix this problem.
ConversionRates data class:
data class ConversionRates(
val AED: Double,
val AFN: Double,
val ALL: Double,
val AMD: Double,
val ANG: Double,
val AOA: Double,
val ARS: Double,
val AUD: Double,
val AWG: Double,
val AZN: Double,
val BAM: Double,
val BBD: Double,
val BDT: Double,
val BGN: Double,
val BHD: Double,
val BIF: Double,
val BMD: Double,
val BND: Double,
val BOB: Double,
val BRL: Double,
val BSD: Double,
val BTN: Double,
val BWP: Double,)
viewModel:
#HiltViewModelclass MainViewModel #Inject constructor(
private val repository: MainRepository,
private val dispatchers: DispatcherProvider) : ViewModel(){
sealed class CurrencyEvent {
class Success(val resultText: String): CurrencyEvent()
class Failure(val errorText: String): CurrencyEvent()
object Loading: CurrencyEvent()
object Empty: CurrencyEvent() }
private val _conversion= MutableStateFlow<CurrencyEvent>(CurrencyEvent.Empty)
val conversion: StateFlow<CurrencyEvent> = _conversion
fun convert(amountStr: String,
fromCurrency: String,
toCurrency: String ){
val fromAmount= amountStr.toFloatOrNull()
if( fromAmount== null){
_conversion.value=CurrencyEvent.Failure("Not a valid amount")
return
}
viewModelScope.launch (dispatchers.io){
_conversion.value= CurrencyEvent.Loading
when( val ratesResponse= repository.getRates(fromCurrency)) {
is Resource.Error -> _conversion.value= CurrencyEvent.Failure(ratesResponse.message!!)
is Resource.Success -> {
val rates = ratesResponse.data!!.conversion_rates
val rate = getRateForCurrency(toCurrency, rates)
if (rate==null){
_conversion.value= CurrencyEvent.Failure("Unexpected Error")
} else {
//val convertedCurrency = round(fromAmount * rate * 100)
_conversion.value= CurrencyEvent.Success(
"$fromAmount $fromCurrency = $toCurrency"
)
}
}
}
}
}
private fun getRateForCurrency(currency: String, rates: ConversionRates) = when (currency) {
"CAD" -> rates.CAD
"HKD" -> rates.HKD
"ISK" -> rates.ISK
"EUR" -> rates.EUR
"PHP" -> rates.PHP
"DKK" -> rates.DKK
"HUF" -> rates.HUF
"CZK" -> rates.CZK
"AUD" -> rates.AUD
"RON" -> rates.RON
"SEK" -> rates.SEK
"IDR" -> rates.IDR
"INR" -> rates.INR
"BRL" -> rates.BRL
"RUB" -> rates.RUB
"HRK" -> rates.HRK
"JPY" -> rates.JPY
"THB" -> rates.THB
"CHF" -> rates.CHF
"SGD" -> rates.SGD
"PLN" -> rates.PLN
"BGN" -> rates.BGN
"CNY" -> rates.CNY
"NOK" -> rates.NOK
"NZD" -> rates.NZD
"ZAR" -> rates.ZAR
"USD" -> rates.USD
"MXN" -> rates.MXN
"ILS" -> rates.ILS
"GBP" -> rates.GBP
"KRW" -> rates.KRW
"MYR" -> rates.MYR
else -> null
}}
CurrencyApi
interface CurrencyApi {
#GET("/v6/68c54e50f924117c29176f8f/latest/USD")
suspend fun getRates(
#Query("base_code") base_code : String
): Response<CurrencyResponse>}
Default Main Repo
class DefaultMainRepository #Inject constructor(
private val api :CurrencyApi): MainRepository {
override suspend fun getRates(base_code: String): Resource<CurrencyResponse> {
return try {
val response = api.getRates(base_code)
val result= response.body()
if (response.isSuccessful && result!=null){
Resource.Success(result)
} else{
Resource.Error(response.message())
}
}catch (e: Exception) {
Resource.Error(e.message?: "An error occured")
}
}}
MainRepo:
interface MainRepository {
suspend fun getRates(base_code: String) : Resource<CurrencyResponse>}

Apperently, kotlin data classes can only contain about 127 arguments, so you have two options.
Break down the response data class into two (RatesAToL and RatesMToZ) and make two requests to the API.
Convert the JSON object (conversion_rates) into a list of objects
Rate(val code: String, val amount: Double)
. This can be done using a Moshi custom adapter.
See code gist here Custom Moshi adapter Full project on GitHub fxConverter
class MoshiJsonAdapter : JsonAdapter<InfoAndRatesResponse>() {
#FromJson
override fun fromJson(reader: JsonReader): InfoAndRatesResponse {
reader.beginObject()
var result = ""
var timeLastUpdateUnix = 0
var timeLastUpdateUtc = ""
var timeNextUpdateUnix = 0
var timeNextUpdateUtc = ""
var baseCode = ""
val rates = mutableListOf<Rate>()
while (reader.hasNext()) {
when (reader.nextName()) {
"result" -> result = reader.nextString()
"time_last_update_unix" -> timeLastUpdateUnix = reader.nextInt()
"time_last_update_utc" -> timeLastUpdateUtc = reader.nextString()
"time_next_update_unix" -> timeNextUpdateUnix = reader.nextInt()
"time_next_update_utc" -> timeNextUpdateUtc = reader.nextString()
"base_code" -> baseCode = reader.nextString()
"conversion_rates" -> {
reader.beginObject()
while (reader.peek() != JsonReader.Token.END_OBJECT) {
val code = reader.nextName()
val amount = when (code) {
baseCode -> reader.nextInt().toDouble()
else -> reader.nextDouble()
}
val infoBaseCode = baseCode
Timber.tag("MyTag")
.d(" code $code amount $amount infoBaseCode $infoBaseCode")
rates.add(
Rate(
code = code,
amount = amount,
infoBaseCode = infoBaseCode,
)
)
}
reader.endObject()
}
else -> reader.skipValue()
}
}
reader.endObject()
return InfoAndRatesResponse(
result = result,
timeLastUpdateUnix = timeLastUpdateUnix,
timeLastUpdateUtc = timeLastUpdateUtc,
timeNextUpdateUnix = timeNextUpdateUnix,
timeNextUpdateUtc = timeNextUpdateUtc,
baseCode = baseCode,
rates = rates
)
}
#ToJson
override fun toJson(writer: JsonWriter, value:
InfoAndRatesResponse?) {
throw UnsupportedOperationException()
}
}

I'm not sure about this, but when it says "Unable to invoke no-arg constructor", to me that sounds like you need to be able to create an instance of CurrencyResponse with no arguments. Maybe try setting some default values? I would give this a shot:
data class ConversionRates(
val AED: Double = 0.0,
val AFN: Double = 0.0,
val ALL: Double = 0.0,
val AMD: Double = 0.0,
val ANG: Double = 0.0,
val AOA: Double = 0.0,
val ARS: Double = 0.0,
val AUD: Double = 0.0,
val AWG: Double = 0.0,
val AZN: Double = 0.0,
val BAM: Double = 0.0,
val BBD: Double = 0.0,
val BDT: Double = 0.0,
val BGN: Double = 0.0,
val BHD: Double = 0.0,
val BIF: Double = 0.0,
val BMD: Double = 0.0,
val BND: Double = 0.0,
val BOB: Double = 0.0,
val BRL: Double = 0.0,
val BSD: Double = 0.0,
val BTN: Double = 0.0,
val BWP: Double = 0.0,
)

Related

How can I improve the verbose code when I use enum in Kotlin?

The are many items in a enum class , I found there ae many verbose code in the function fun getLevel.
How can I improve it?
Code A
enum class ELevel(private val labelId: Int, val alarmed: Boolean){
Normal(R.string.Normal,false),
Leaves(R.string.Leaves,false),
Whispering(R.string.Whispering,false),
Quiet(R.string.Quiet,false),
Refrigerator(R.string.Refrigerator,false),
Electric(R.string.Electric,false),
Washing(R.string.Washing,true),
Alarm(R.string.Alarm,true),
Subway(R.string.Subway ,true),
Factory(R.string.Factory,true),
Car(R.string.Car,true),
Ambulance(R.string.Ambulance,true);
fun getLabel(mContext: Context) = mContext.getString(labelId)
companion object {
fun getLevel(soundValue: Double): ELevel {
var temp = Normal
val i = soundValue.toInt()
if (i in 1..10) {
temp = Normal
}
if (i in 11..20) {
temp = Leaves
}
...
if (i in 101..110) {
temp = Car
}
if (i in 111..120) {
temp = Ambulance
}
return temp
}
}
In the same way that you have associates a labelId and alarmed flag with each of the enum constants, you can add an additional maxSoundLevel property:
enum class ELevel(
private val labelId: Int,
val alarmed: Boolean,
val maxSoundLevel: Int,
){
Normal(R.string.Normal,false, 10),
Leaves(R.string.Leaves,false, 20),
...
}
Then you can do:
companion object {
fun getLevel(soundValue: Double): ELevel =
// assuming the max sound levels are in ascending order
values().firstOrNull { soundValue.toInt() <= it.maxSoundLevel }
// if there is no match, throw exception. You can also just return the nullable ELevel
?: throw IllegalArgumentException("Unknown sound")
}
One way could be to create an abstract val range and define it for each enum. After that you could simply check and get the first enum that have your soundValue in his range.
enum class ELevel(private val labelId: Int, val alarmed: Boolean) {
Normal(R.string.Normal, false) {
override val range: IntRange = 1..10
},
Leaves(R.string.Leaves, false) {
override val range: IntRange = 11..20
},
Whispering(R.string.Whispering, false) {
override val range: IntRange = ...
},
Quiet(R.string.Quiet, false) {
override val range: IntRange = ...
},
Refrigerator(R.string.Refrigerator, false) {
override val range: IntRange = ...
},
Electric(R.string.Electric, false){
override val range: IntRange = ...
},
Washing(R.string.Washing, true){
override val range: IntRange = ...
},
Alarm(R.string.Alarm, true){
override val range: IntRange = ...
},
Subway(R.string.Subway, true){
override val range: IntRange = ...
},
Factory(R.string.Factory, true){
override val range: IntRange = ...
},
Car(R.string.Car, true) {
override val range: IntRange = 101..110
},
Ambulance(R.string.Ambulance, true) {
override val range: IntRange = 111..120
};
fun getLabel(mContext: Context) = mContext.getString(labelId)
abstract val range: IntRange
companion object {
fun getLevel(soundValue: Double): ELevel =
values().first { it.range.contains(soundValue.toInt()) }
}
}
If the IDs of the Strings are exact matches for the enum value names, you can also use identifier look-up to shorten your code a little bit more.
enum class ELevel(
val alarmed: Boolean,
private val maxSoundLevel: Int,
){
Normal(false, 10),
Leaves(false, 20),
//...
;
private var labelId = 0
fun getLabel(context: Context){
if (labelId == 0) {
labelId = context.resources.getIdentifier(name, "id", context.packageName)
}
return context.getString(labelId)
}
}

How to solve this strong dependency between those classes?

I have two classes A and B.
Class A has several properties. One of them are an instance of class B.
At some point in the main function I will define an instance a of A. I will need to do some computation on its property of type B.
This computation, however, needs another property of a.
The result is a.property3.computation(a.property1,someValue). I think it's ugly.
Here is some "pseudo-code" (in Kotlin but I am facing the same problem using other languages as well):
class B {
val property : Map<String,Int>
fun computation(val parameter1: Int, val parametre2: Double) : Int {
//doing some computation
return result
}
}
class A {
var property1 : Int
var property2 : Stirng
var property3 : B
}
fun main (){
val someValue = 0.4 //It's here to show the idea that the function `computation` needs also some other arguments that does not come from `A`'s propery
val a = A()
val result = a.property3.computation(a.property1,someValue) // here is the line that bothers me !
}
I think you should use Builder design pattern to remove computation function from B class like this:
class B {
val properties : MutableMap<String,Int> = HashMap()
fun setProperty(name: String, value: Int) {
this.properties[name] = value
}
}
class A {
var property1 : Int = 0
var property2 : String = ""
var property3 : B = B()
}
class Calculator(builder: Builder) {
private val property1 = builder.property1
private val someValue = builder.someValue
private val properties = builder.properties
companion object {
fun builder() = Builder()
}
fun computation() : Int {
//doing some computation
val result = property1 + someValue.toInt() + properties.getOrDefault("value", 0)
return result
}
class Builder {
var property1: Int = 0
var someValue: Double = 0.0;
var properties : MutableMap<String,Int> = HashMap()
fun property1(property1: Int): Builder {
this.property1 = property1
return this
}
fun someValue(someValue: Double): Builder {
this.someValue = someValue
return this
}
fun properties(properties : Map<String,Int>): Builder {
this.properties.putAll(properties);
return this
}
fun build(): Calculator {
return Calculator(this)
}
}
}
fun main (){
val someValue = 0.4 //It's here to show the idea that the function `computation` needs also some other arguments that does not come from `A`'s propery
val a = A()
a.property1 = 10
a.property3.setProperty("value", 20)
val result = Calculator.builder()
.properties(a.property3.properties)
.property1(a.property1)
.someValue(someValue)
.build()
.computation()
println(result)
}
May be you want this?
fun main (){
val someValue = 0.4
val a = A()
val result = with(a) {
property3.computation(property1,someValue)
}
}

Using Kotlin to build classes with Generic data types

I'm in the process of building my Kotlin and general programming knowledge and trying to follow good practices while doing so. I am working on a project with some important matrix manipulation so I decided I would build my own Matrix class and define the logic myself.
I could have just built it two accept Doubles. But I wanted to build it to support any numeric type and even allow other classes that I define like fractions or complex numbers.
I also wanted to make the values of the matrix private so that you only access values through specific methods. mostly because that seems best practice development for future projects dealing with secure data.
The Issue: Now set up as an interface. still room for improvement. One thing I was struggling to do was to find a way to have a parameter for the interface, that stores the multiplicative identity (1) and one for the additive identity (0) that is implemented for each class. For some reason this didn't seem to work.
interface MyNumber<T> {
operator fun plus(other: T): MyNumber<T>
operator fun unaryMinus(): MyNumber<T>
operator fun minus(other: T): MyNumber<T>
operator fun times(other: T): MyNumber<T>
operator fun div(other: T): MyNumber<T>
operator fun compareTo(other: T): Int
}
class MyInt(val value: Int): MyNumber<MyInt> {
override fun plus(other: MyInt) = MyInt(value + other.value)
override fun unaryMinus() = MyInt(-value)
override fun minus(other: MyInt) = MyInt(value - other.value)
override fun times(other: MyInt) = MyInt(value * other.value)
override fun div(other: MyInt) = MyInt(value / other.value)
override fun toString() = value.toString()
override fun equals(other: Any?): Boolean {
return when{
other is MyInt -> value == other.value
other is Int -> value == other
else -> false
}
}
override fun compareTo(other: MyInt) = value.compareTo(other.value)
}
class MyLong(val value: Long): MyNumber<MyLong> {
override fun plus(other: MyLong) = MyLong(value + other.value)
override fun unaryMinus() = MyLong(-value)
override fun minus(other: MyLong) = MyLong(value - other.value)
override fun times(other: MyLong) = MyLong(value * other.value)
override fun div(other: MyLong) = MyLong(value / other.value)
override fun toString() = value.toString()
override fun equals(other: Any?): Boolean {
return when{
other is MyLong -> value == other.value
other is Long -> value == other
else -> false
}
}
override fun compareTo(other: MyLong) = value.compareTo(other.value)
}
class MyDouble(val value: Double): MyNumber<MyDouble> {
override fun plus(other: MyDouble) = MyDouble(value + other.value)
override fun unaryMinus() = MyDouble(-value)
override fun minus(other: MyDouble) = MyDouble(value - other.value)
override fun times(other: MyDouble) = MyDouble(value * other.value)
override fun div(other: MyDouble) = MyDouble(value / other.value)
override fun toString() = value.toString()
override fun equals(other: Any?): Boolean {
return when{
other is MyDouble -> value == other.value
other is Double -> value == other
else -> false
}
}
override fun compareTo(other: MyDouble) = value.compareTo(other.value)
}
class Fraction private constructor(val num: Long, val div: Long): MyNumber<Fraction> {
data class Builder(var numerator: Long = 0L, var divisor: Long = 1L) {
fun build(numerator: Long, divisor: Long): Fraction {
if (divisor == 0L) {throw ArithmeticException("Cannot divide by Zero")}
this.numerator = numerator
this.divisor = divisor
val gcd = gcd(numerator, divisor)
val sign = sign(divisor.toDouble()).toLong()
return Fraction(sign * numerator / gcd, sign * divisor / gcd)
}
}
val value = num.toDouble()/div
override fun plus(other: Fraction) =
Builder().build(num * other.div + div * other.num, div * other.div)
override fun unaryMinus() = Fraction(-num, div)
override fun minus(other: Fraction) = this + -other
override fun times(other: Fraction) =
Builder().build(num * other.num, div * other.div)
fun invert() = Builder().build(div, num)
override fun div(other: Fraction) = this * other.invert()
override fun toString() = "$num / $div"
override fun equals(other: Any?): Boolean {
return when{
other is Fraction -> num * other.div == div * other.num
other is Double -> value == other
else -> false
}
}
override fun compareTo(other: Fraction) = value.compareTo(other.value)
}
class Complex(val real: Double, val image: Double): MyNumber<Complex> {
val abs = sqrt(real * real + image * image)
override fun plus(other: Complex) = Complex(real + other.real, image + other.image)
override fun unaryMinus() = Complex(-real, -image)
override fun minus(other: Complex) = this + -other
operator fun times(scalar: Double) =
Complex(real * scalar, image * scalar)
operator fun div(scalar: Double) = this * (1/scalar)
override fun times(other: Complex) =
Complex(real * other.real - image * other.image, real * other.image + image * other.real)
fun conj() = Complex(real, -image)
fun invert() = this.conj() / (this * this.conj()).abs
override fun div(other: Complex) = this * other.invert()
override fun toString() = "$real + ${image} i"
override fun equals(other: Any?): Boolean {
return when{
other is Complex -> real == other.real && image == other.image
other is Double -> real == other && image == 0.0
else -> false
}
}
override fun compareTo(other: Complex) = real.compareTo(other.real)
}
#Suppress("UNCHECKED_CAST")
class Matrix<T: MyNumber<T>>(val width: Int, val height: Int, private val values: List<List<MyNumber<T>>>) {
data class Builder(var width: Int = 0, var height: Int = 0) {
fun parameters(width: Int, height: Int) {
this.width = width
this.height = height
}
fun <T: MyNumber<T>> build(data: List<T>): Matrix<T> {
val values = List(height) { j -> List(width) {
i -> data[(j * width + i) % data.size]
}}
return Matrix(width, height, values)
}
}
fun getRowOrNull(j: Int): List<MyNumber<T>>? {
if (j in 0 until height) {
return values[j]
}
return null
}
fun getIndexed(i: Int, j: Int): MyNumber<T> {
return values[j][i]
}
fun getColOrNull(i: Int): List<MyNumber<T>>? {
if (i in 0 until width) {
return List(height) { j -> values[j][i]}
}
return null
}
operator fun plus(other: Matrix<T>): Matrix<T>? {
if (width != other.width || height != other.height ) {
return null
}
val newData = List(height) { j -> List(width) {
i -> getIndexed(i, j).plus(other.getIndexed(i, j) as T)
}}
return Matrix(width, height, newData)
}
operator fun times(other: Matrix<T>): Matrix<T>? {
if (width != other.height) {
return null
}
val newData = List(height) { j -> List(other.width) {
i -> values[j].mapIndexed { k, v -> (v * other.values[k][i] as T) }
.reduce{acc, it -> acc + it as T }
}}
return Matrix(other.width, height, newData)
}
fun transpose(): Matrix<T> {
val newData = List(width) { i -> List(height) {
j -> values[j][i]
}}
return Matrix(height, width, newData)
}
fun getMinor(i: Int, j: Int): Matrix<T>? {
if (i in 0 until width && j in 0 until height) {
val newData = List(height - 1) { y ->
List(width - 1) { x ->
when {
x < i && y < j -> values[y][x]
x < i -> values[y + 1][x]
y < j -> values[y][x + 1]
else -> values[y + 1][x + 1]
}
}
}
return Matrix(width - 1, height - 1, newData)
}
return null
}/*
fun determinate(): T {
}
fun coFactor(i: Int, j: Int): T {
sign = if ((i + j) % 2 == 0) 1
}*/
override fun toString(): String {
var string = ""
for (j in 0 until height) {
string += getRowOrNull(j)?.toString() + "\n"
}
return string
}
}

Deep merging data classes in Kotlin

How can I do a recursive / deep merge of two data classes in Kotlin? Something like this:
import kotlin.reflect.*
import kotlin.reflect.full.*
data class Address(
val street: String? = null,
val zip: String? = null
)
data class User(
val name: String? = null,
val age: Int? = null,
val address: Address? = null
)
inline fun <reified T : Any> T.merge(other: T): T {
val nameToProperty = T::class.declaredMemberProperties.associateBy { it.name }
val primaryConstructor = T::class.primaryConstructor!!
val args = primaryConstructor.parameters.associate { parameter ->
val property = nameToProperty[parameter.name]!!
val type = property.returnType.classifier as KClass<*>
if (type.isData) {
parameter to this.merge(other) //inline function can't be recursive
} else {
parameter to (property.get(other) ?: property.get(this))
}
}
return primaryConstructor.callBy(args)
}
val u1 = User(name = "Tiina", address = Address(street = "Hämeenkatu"))
val u2 = User(age = 23, address = Address(zip = "33100"))
u1.merge(u2)
// expected: User(age = 23, name= "Tiina", address = Address(zip = "33100", street = "Hämeenkatu")
related: Combining/merging data classes in Kotlin
There were several problems in the posted code,
unnecessary reification and inlining
when type isData was detected instead of merging the values of the property merge on this with the other was called, so it became endless recursion.
get cannot be used on KProperty1<out T, Any?> because of the variance
some non-idiomatic stuff which works, but can be made better
Here's the fixed version. For production I would've added some checks and error messages, but this should work for "happy path" and hopefully give you the base to build on:
import kotlin.reflect.KClass
import kotlin.reflect.KParameter
import kotlin.reflect.KProperty1
import kotlin.reflect.full.declaredMemberProperties
import kotlin.reflect.full.isSubclassOf
import kotlin.reflect.full.primaryConstructor
data class Address(
val street: String? = null,
val zip: String? = null
)
data class User(
val name: String? = null,
val age: Int? = null,
val address: Address? = null,
val map: Map<String, Int>? = null
)
fun <T> mergeData(property: KProperty1<out T, Any?>, left: T, right: T): Any? {
val leftValue = property.getter.call(left)
val rightValue = property.getter.call(right)
return rightValue?.let {
if ((property.returnType.classifier as KClass<*>).isSubclassOf(Map::class)) (leftValue as? Map<*, *>)?.plus(it as Map<*, *>)
else leftValue?.merge(it)
} ?: rightValue ?: leftValue
}
fun <T> lastNonNull(property: KProperty1<out T, Any?>, left: T, right: T) =
property.getter.call(right) ?: property.getter.call(left)
fun <T : Any> T.merge(other: T): T {
val nameToProperty = this::class.declaredMemberProperties.associateBy { it.name }
val primaryConstructor = this::class.primaryConstructor!!
val args: Map<KParameter, Any?> = primaryConstructor.parameters.associateWith { parameter ->
val property = nameToProperty[parameter.name]!!
val type = property.returnType.classifier as KClass<*>
when {
type.isData || type.isSubclassOf(Map::class) -> mergeData(property, this, other)
else -> lastNonNull(property, this, other)
}
}
return primaryConstructor.callBy(args)
}
// verification
val u1 = User(name = "Tiina", address = Address(street = "Hämeenkatu"), map = mapOf("a" to 1))
val u2 = User(age = 23, address = Address(zip = "33100"), map = mapOf("b" to 2))
check(
u1.merge(u2) == User(
age = 23,
name = "Tiina",
address = Address(zip = "33100", street = "Hämeenkatu"),
map = mapOf("a" to 1,"b" to 2)
)
) {
"doesn't work"
}
println("Works!")

Kotlin Comparator Compilation Error in IntelliJ

Using Kotlin 1.2.41-release and given a List<Pair<Int, Int>>, the following code generates a compilation error in Intellij, although Gradle command line build works.
sortedWith(compareBy({ it.first }, { it.second }))
Cannot choose among the following candidates without completing type inference.
public fun <T> compareBy(vararg selectors: (???) -> Comparable<*>?): kotlin.Comparator<???> defined in kotlin.comparisons
public fun <T> compareBy(vararg selectors: (Pair<Int, Int>) -> Comparable<*>?): kotlin.Comparator<Pair<Int, Int>> defined in kotlin.comparisons
How can I fix this?
Edit:
edges
.map {
it.either.run {
val p = this
val q = it.other(this)
val min = min(p, q)
if (min == p) p to q else q to p
}
}
.sortedWith(compareBy({ it.first }, { it.second }))
.toList()
where, edges is Iterable<Edge>
class Edge(private val v: Int, private val w: Int, val weight: Double) : Comparable<Edge> {
val either: Int
get() = v
fun other(vertex: Int): Int {
return if (v == vertex) w else v
}
override fun compareTo(other: Edge): Int {
return weight.compareTo(other.weight)
}
override fun toString(): String {
return "Edge(v=$v, w=$w, weight=$weight)"
}
}