How to return a listmap with non null item, from a map? - kotlin

I have a piece of code as below (simplified to explain the issue). From the rawData, I would like to filter out those that doesn't have a converter type provided in converter, and then for the remaining, convert the data to listitem
data class RawData(val type: String, val data: Data)
interface Converter {
fun convert(data: Data): ListItem
}
fun transform(): List<ListItem> {
val providerTypeMap = modelViewProvider.associateBy({it.type}, {it})
return rawDataList.filter {
converter[it.type] != null
}.map {
converter[it.type]?.create(it.data) ?: object: ListItem {}
}
}
Note: I want the return type as List<ListItem> and not List<ListItem?>. In order to do that, I need to have this line
converter[it.type]?.create(it.data) ?: object: ListItem {}
Which to me the ? and ?: is pretty ugly since we know by then, we already filter and only keep that converter[it.type] != null
Is there a way for me to get rid of the ? and ?: ListItem{} in my code?

There is a solution:
return rawDataList.mapNotNull {
converter[it.type]?.create(it.data)
}
But i don't know in which Kotlin's version mapNotNull() method appeared. If you haven't it you can use construction map {}.filterNotNull() or write your own mapNotNull extension method.

Related

How to call constructor default lambda using Kotlin Refelction?

Trying to call lambda provided by MyClass constructor using Kotlin Reflection.
data class MyClass(
var magic:Int=2,
var lambdaValue: ()->String = { //trying to call this lambda from reflection
"Working"
},
)
fun main(args: Array<String>) {
val clazz=MyClass::class
val obj=clazz.createInstance()
val kProperty=clazz.memberProperties
clazz.constructors.forEach{cons-> // for each construtor
cons.parameters.forEach{ parameter-> // looping through constructor parameters
val property=kProperty.find { it.name==parameter.name } // finding the exact property
print(parameter.name+" : ")
if(parameter.type.arguments.isEmpty()) // if empty Int,Float
{
println(property?.get(obj))
}else{
println(property?.call(obj)) // unable to call lambda
}
}
}
}
property.call(obj) returns Any which is not invokable. Any solution?
Expected:
magic : 2
lambdaValue : Working
Frankly speaking, I'm not sure what was your idea behind parameter.type.arguments.isEmpty(). It seems unrelated to what you try to do.
If we have a value of the property already, we can simply check its type and if its is a function then invoke it:
val value = kProperty.find { it.name==parameter.name }!!.get(obj)
print(parameter.name+" : ")
when (value) {
is Function0<*> -> println(value())
else -> println(value)
}
I think usefulness of such a code in generic case isn't very high. This code doesn't know what is the function and if it is going to return a value or perform some action, etc. Maybe in your specific case it is more useful.

What is the type of a Kotlin 'data class'?

I have a situation where I need to create a copy of data class object. I don't know in advance which of the many data classes I have will come in into the function. I do know, however, that only data classes will be used as input to this function.
This is what didn't work:
fun doSomething(obj: Any): Any {
obj.copy(...) // <- there's no 'copy' on Any
...
}
This is what I really like to do:
fun doSomething(obj: KAnyDataClass): KAnyDataClass {
obj.copy(...) // <- works, data classes have a 'copy' method
...
}
I'm not a Kotlin developer, but it looks like the language does not support dynamic dispatch or traits. You might find success with the dynamic type, which just turns off the type-checker so it won't yell at you for using a method that it doesn't know about. However this opens up the possibility of a runtime error if you pass an argument that actually doesn't have that method.
There is no class or interface for data classes, but we know from the documentation of data classes that there are derived functions componentN and copy in each data class.
We can use that knowledge to write an abstract copy method that calls the copy method of a given arbitrary data class using reflection:
fun <T : Any> copy(data: T, vararg override: Pair<Int, Any?>): T {
val kClass = data::class
if (!kClass.isData) error("expected a data class")
val copyFun = kClass.functions.first { it.name == "copy" }
checkParameters(override, kClass)
val vals = determineComponentValues(copyFun, kClass, override, data)
#Suppress("UNCHECKED_CAST")
return copyFun.call(data, *vals) as T
}
/** check if override of parameter has the right type and nullability */
private fun <T : Any> checkParameters(
override: Array<out Pair<Int, Any?>>,
kClass: KClass<out T>
) {
override.forEach { (index, value) ->
val expectedType = kClass.functions.first { it.name == "component${index + 1}" }.returnType
if (value == null) {
if (!kClass.functions.first { it.name == "component${index + 1}" }.returnType.isMarkedNullable) {
error("value for parameter $index is null but parameter is not nullable")
}
} else {
if (!expectedType.jvmErasure.isSuperclassOf(value::class))
error("wrong type for parameter $index: expected $expectedType but was ${value::class}")
}
}
}
/** determine for each componentN the value from override or data element */
private fun <T : Any> determineComponentValues(
copyFun: KFunction<*>,
kClass: KClass<out T>,
override: Array<out Pair<Int, Any?>>,
data: T
): Array<Any?> {
val vals = (1 until copyFun.parameters.size)
.map { "component$it" }
.map { name -> kClass.functions.first { it.name == name } }
.mapIndexed { index, component ->
override.find { it.first == index }.let { if (it !== null) it.second else component.call(data) }
}
.toTypedArray()
return vals
}
Since this copy function is generic and not for a specific data class, it is not possible to specify overloads in the usual way, but I tried to support it in another way.
Let's say we have a data class and element
data class Example(
val a: Int,
val b: String,
)
val example: Any = Example(1, "x")
We can create a copy of example with copy(example) that has the same elements as the original.
If we want to override the first element, we cannot write copy(example, a = 2), but we can write copy(example, 0 to 2), saying that we want to override the first component with value 2.
Analogously we can write copy(example, 0 to 3, 1 to "y") to specify that we want to change the first and the second component.
I am not sure if this works for all cases since I just wrote it, but it should be a good start to work with.

Kotlin function return with any one return type from two different data type without specifying Any as a return type?

I want to allow any one of these two return type (ApiResponse || ErrorResponse). But Return Type should not be a object or Any.
fun getAllUser() : Any? {
val flag = true
return if(flag){
ApiResponse(true)
} else {
ErrorResponse(500)
}
}
With return type (Any), Not able to write an extension function to do specific action with with two different return type. I want t specify Two responses.
In My case, I want to write different Extension function for ApiResponse & ErrorResponse class.
Is it possible to return either ErrorResponse or ApiResponse in a same function?
Create a sealed interface that both of your classes implement:
sealed interface Response<out T>
data class ApiResponse<T>(val data: T): Response<T>
data class ErrorResponse(val errorCode: Int): Response<Nothing>
fun getAllUser() : Response<Boolean> {
val flag = true
return if(flag){
ApiResponse(true)
} else {
ErrorResponse(500)
}
}
Then you can write extension functions that handle either type:
fun Response<Boolean>.foo() {
when (this) {
is ApiResponse<Boolean> -> { TODO() }
is ErrorResponse -> { TODO() }
}
}
Inside the branches of this when statement, the input will be smart cast to the appropriate type.
I got a Idea to return either ErrorResponse or ApiResponse in a same function.
By using [Λrrow][1] library I'm able to achieve this like the following function.
fun getAllUser() : Either<ErrorResponse,ApiResponse>? {
val flag = true
ResponseEntity(ErrorResponse(500),HttpStatus.INTERNAL_SERVER_ERROR)
ResponseEntity.internalServerError().build<ErrorResponse>()
val response: Either<ErrorResponse,ApiResponse> = return if(flag){
Either.right(ApiResponse(true))
} else {
Either.left(ErrorResponse(500))
}
return response
}
I suggest using Result class. Either the one provided by Kotlin or, even better, your own implementation. Here is one of the examples of using custom implementation, along with the explanation. This should give you all the information you need.

Сheck if map contains substring. Kotlin

I have a
val map = Map<String,String>
map.put("Nurseiyt","android")
I want to get a value by subString like:
map["Nurs"] should return "android"
is it possible?
Use kotlin.Collections, there are methods like filter.
Two things - it's better to use regular expression. So, you can even get better control what will be returned. And the second one, there can be more than one elements matched to that regex. So that's why I return list.
fun <T> substringKey(map: Map<String, T>, regex: Regex): List<T> {
return map.filter { it.key.contains(regex) }
.map { it.value }
}
If you want to use that notation you need to create your own map and override proper operator. What's worth to notice, you cannot return list of values then. So, in this case I just return first found value.
class SubstringMap<V> : HashMap<String, V>() {
override operator fun get(key: String): V? {
return this.entries.first { it.key.contains(key) }.value
}
}
fun main() {
val map = SubstringMap<String>()
map["Nurseiyt"] = "android"
println(map["Nurs"]) // "android"
}
And as the last thing - in kotlin you can create your own operator, like withKeyPart. This would be much better than overriding default operator (because I wouldn't expect that [] operator will work in different way than usual.
infix fun <V> Map<String, V>.withKeyPart(keyPart: String): List<V> {
return this.filter { it.key.contains(keyPart) }
.map { it.value }
}
and then call it like this:
fun main() {
val map = HashMap<String, String>()
map withKeyPart "KeyPart" // infix notation
map.withKeyPart("KeyPart") // standard call
}
Filtering the map, as per other answers, is simple and straightforward, but it doesn't scale well; it takes time proportional to the size of the map, so if the map could grow big, it could get very slow.
If you're always going to be searching for a leading substring, i.e. the start of a map key, then a better general solution is a data structure called a trie.  This lets you search efficiently, with just one lookup per character.
Of course, writing one from scratch may not be justified for your project.  But there are third-party implementations you could use, such as this one in Apache Commons.  Or see the answers to this question.
write top level function like this
fun HashMap<String, String>.getContainskeyValue(search: String): String?
{
var returnList = ArrayList<String?>()
this.keys.filter { it.contains(search) }.map {
returnList.add(this[it])
}
return returnList.first()
//if you want all keys 'contains' values just return list
/* Ex
map.put("Nurseiyt", "android")
map.put("Nurseiyt1", "androidone")
map.put("Nurseirt2", "andrrroidtwo")
val isContainsdata = map.getContainskeyValue("N")
println(" result " + containsdata)
output :result [andrrroidtwo, android, androidone]
*/
}
then call like this
val map = HashMap<String, String>()
map.put("Nurseiyt", "android")
val containsdata = map.getContainskeyValue("Nurs")
println(" result " + containsdata)
output
android

How to use Kotlin fold function to convert an array into a map?

I am trying to convert an Array via fold into an indexed Map. Somehow IntelliJ flags that when I return the accumulator that it expects Unit. When I remove the return it complains that I require the datatype I originally wanted to return.
The code is as follows (Item is just a data class)
constructor(vararg items: Item){
val itemMap = items.fold(mutableMapOf<Int, MutableList<Item>>(), { acc, item ->
if (acc.containsKey(item.state)) {
acc[item.state]?.add(item)
} else {
acc.put(item.state, mutableListOf(item))
}
return acc
})
}
Its a bit late here so I probably miss something very obvious. Any help would be very appreciated.
Thanks
Use the qualified return#fold operator instead of return. In Kotlin, return without a qualifier means 'return from the innermost fun (ignoring lambdas)'.
val itemMap = items.fold(mutableMapOf<Int, MutableList<Item>>(), { acc, item ->
if (acc.containsKey(item.state)) {
acc[item.state]?.add(item)
} else {
acc.put(item.state, mutableListOf(item))
}
return#fold acc
})
See Whats does “return#” mean?, Return at Labels in the language reference.
Or just use the result expression, omitting return:
val itemMap = items.fold(mutableMapOf<Int, MutableList<Item>>(), { acc, item ->
if (acc.containsKey(item.state)) {
acc[item.state]?.add(item)
} else {
acc.put(item.state, mutableListOf(item))
}
acc
})
Basically, this kind of fold is implemented in the standard library: see .groupBy { ... }.