What is the best way to search a map and find the first key that matches a predicate on value or null otherwise? My code below looks too verbose for kotlin standard. Please help.
fun <K, V> find(map : Map<K, V?>, predicate: (V?) -> Boolean): K? {
var key : K? = null
map.forEach { it ->
if(predicate(it.value)) {
key = it.key
return#forEach
}
}
return key
}
map.entries.firstOrNull { predicate(it.value) }?.key
entries is used to make the Map iterable, and is "free" (in that it doesn't require iterating over the map). Of course, it enables all collection extension functions missing on Map itself, not just firstOrNull.
(You can also replace firstOrNull with find; they are equivalent here.)
You don't need var key, you can instead immediately return the key once found and return null in the end.
In the lambda passed to forEach, you can use parameter destructuring to access the key and value without using it:
fun <K, V> find(map : Map<K, V?>, predicate: (V?) -> Boolean): K? {
map.forEach { (key, value) ->
if (predicate(value)) {
return key
}
}
return null
}
Also, you can convert the map parameter to receiver, making it an extension function that can be called on a map instance:
fun <K, V> Map<K, V>.findKeyByValue(predicate: (V) -> Boolean): K? {
forEach { (key, value) ->
if (predicate(value)) {
return key
}
}
return null
}
val result = myMap.findKeyByValue { it > 0 }
You can use filter for search a map and find the first key
for example
var arr = mutableMapOf<Any, Any>()
arr.put("1", "dax1")
arr.put("2", "dax2")
arr.put("3", "dax3")
arr.put("4", "dax4")
val key = arr.filter {
it.value.equals("dax5")
}.keys
if (key.isNotEmpty()) {
Log.e("key", key.elementAt(0).toString())
} else {
Log.e("key", "Key not found")
}
Hope this will help you
Use a combination of filter and firstOrNull
val firstKey = map.keys.filter { it == 1 }.firstOrNull()
To make it lazy, convert it to a sequence before:
val firstKey = map.keys.asSequence().filter { it == 1 }.firstOrNull()
Related
I have a bunch of lookup tables indexed by key that I would like instantiate lazily (i.e. the tables are expensive to compute and I only expect some of them to be used on any given execution of the code).
private var myLazyMap: Map<KeyClass, TableClass> by lazy { ...}
Doesn't work as that makes the map object itself lazy, which isn't right. I think I may need to write a custom delegate, but I still can't see how to embed that into the map object.
I could wrap TableClass with something like
class LazyTable(val param: TableClassParameter) {
private var table: TableClass by lazy { TableClass(param) }
fun wrappedTableFun(): ResultClass {
return table.tableFun()
}
}
But this does mean the class is wrong and it feels like a hack. Can this be done in a neater way?
It could be implemented in multiple ways, depending on your needs. Probably the easiest is to use a map of lazy values directly:
val map = mutableMapOf<KeyClass, Lazy<TableClass>>()
map[myKey1] = lazy { createTable1() }
map[myKey2] = lazy { createTable2() }
val table = map[myKey1]?.value
If we want to not expose Lazy to the users of the map, we need to create our own LazyMap. One way is to use a map similar to above and just hide Lazy from the user:
class LazyMap<K, V>(
private val map: Map<K, Lazy<V>>
) {
operator fun get(key: K): V? = map[key]?.value
}
Another solution is to use a function that creates values when needed:
class LazyMap<K, V>(
private val compute: (K) -> V
) {
private val map = mutableMapOf<K, V>()
operator fun get(key: K): V? = map.getOrPut(key) { compute(key) }
}
We can also use a separate compute function per each key, as in the answer by #tibtof .
A partial implementation could be something like this:
class LazyMap<K, V>(val lazyVals: Map<K, () -> V>, val cache: MutableMap<K, V> = mutableMapOf()) : Map<K, V> by cache {
companion object {
fun <K, V> lazyMapOf(vararg entries: Pair<K, () -> V>): LazyMap<K, V> = LazyMap(mapOf(*entries))
}
override fun get(key: K): V? = cache[key] ?: lazyVals[key]?.let { cache[key] = it(); cache[key] }
}
fun main() {
val lazyMap = lazyMapOf(
1 to { println("computing one"); "one" },
2 to { println("computing two"); "two" }
)
println("get 2")
println(lazyMap[2])
println("get 1")
println(lazyMap[1])
println("get 0")
println(lazyMap[0])
println("get 2 again")
println(lazyMap[2])
}
An we can observe the lazyness in the output:
get 2
computing two
two
get 1
computing one
one
get 0
null
get 2 again
two
Does Kotlin have something to filter a collection and return the matching indexes?
E.g. like Groovy's findIndexValues:
http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Iterable.html#findIndexValues(groovy.lang.Closure)
Something like:
fun <T> List<T>.findIndexValues(predicate: (T) -> Boolean): List<Int> {
var indexValues = mutableListOf<Int>()
this.forEachIndexed { index, it ->
if (predicate(it)) {
indexValues.add(index)
}
}
return indexValues
}
The simplest way I can think of to do this is to use mapIndexedNotNull:
fun <T> List<T>.findIndexValues(predicate: (T) -> Boolean): List<Int> =
mapIndexedNotNull { i, t -> i.takeIf { predicate(t) } }
I don't believe there's a function for this in the standard library.
There are basically 2 simple ways according to me.
//say there is a List x of Strings
val x = listOf<String>()
//I don't believe you are looking for this.
//string is the required String of x at index.
for ((index, string) in x.withIndex()) {
TODO()
}
//2nd method is using filterIndexed
/**
* Returns a list containing only elements matching the given predicate.
* #Params: predicate - function that takes the index of an element and the element itself and returns the result of predicate evaluation on the element.
*/
x.filterIndexed { index, string ->
TODO()
}
I like #Sam's answer, but I find this implementation to be slightly more readable as it filters explicitly on predicate as opposed to implicitly via null:
fun <T> List<T>.findIndexValues(predicate: (T) -> Boolean): List<Int> =
withIndex().filter { (_, t) -> predicate(t) }.map { it.index }
I am tinkering around with Kotlin and I am trying to wrap my head around how nullable variables work in Kotlin. Here I have a piece of code that does a boolean check to see if a vehicle is over capacity. Is the implementation a good way to work with nullable variables or is there a more elegant way ?
class Route(var vehicle: Vehicle?, var jobs: List<Job>?) {
constructor()
constructor(vehicle: Vehicle?)
fun isOverCapacity() : Boolean {
val vehicleCapacity = vehicle?.capacity
if (vehicleCapacity != null){
val totalDemand = jobs?.sumBy { job -> job.demand }
if (totalDemand != null) {
return totalDemand > vehicleCapacity
}
}
return false
}
}
Thanks a lot!
fun isOverCapacity(): Boolean {
val vehicleCapacity = vehicle?.capacity ?: return false
val totalDemand = jobs?.sumBy { job -> job.demand } ?: return false
return totalDemand > vehicleCapacity
}
What does ?: do in Kotlin? (Elvis Operator)
By using kotlin std-lib dsl functional operators like let, run, also, apply, use.
Use of ?. -> if the object/value is not null then only call the next function.
let -> returns the result of lambda expression.
run -> returns the result of lambda expression passing this as receiver.
also -> does operation and returns itself unlike the result of lambda.
apply -> does operation and returns itself unlike the result of lambda passing this as receiver.
use -> returns the result of lambda expression and closes the Closeable resource.
You can simplify the code as follows:
fun isOverCapacity() : Boolean =
vehicle?.capacity?.let { vehicleCapacity ->
jobs?.sumBy { job -> job.demand }?.let { totalDemand ->
totalDemand > vehicleCapacity
}
} ?: false
I'm trying to write a function that maps a String and Int? into a pair, then filters for non null second values in the pair, before continuing to map.
My code looks like this:
val ids: List<String> = listOf("a", "b", "c")
val ints: Map<String, Int?> = mapOf("a" to 1, "b" to 2, "c" to null)
ids.map { id: String ->
Pair(id, ints[id])
}.filter { pair -> pair.second != null}.map { pair: Pair<String, Int> ->
func(id, pair.second)
}
The problem is that the second map has the error:
Type inference failed: Cannot infer type parameter T in
inline fun <T, R> kotlin.collections.Iterable<T>.map ( transform (T) -> R ): kotlin.collections.List<R>
This looks like because the compiler does not know to smart cast my Iterable<Pair<String, Int?>> into an Iterable<Pair<String, Int>> after my filter. What can I do instead to solve this?
Kotlin's smart cast is usually not applicable outside method boundaries. However, there are a couple of ways you can achieve your goal anyway.
First, you can simply tell the compiler that the second value of the pair is never null by using the !! operator like so:
ids.map { id: String -> Pair(id, ints[id]) }
.filter { pair -> pair.second != null }
.map { pair: Pair<String, Int?> -> func(pair.second!!) }
Second, you can reverse the order of filter and map and apply the !! operator earlier:
ids.filter { id: String -> ints[id] != null }
.map { id: String -> id to ints[id]!! } //equivalent to Pair(id, ints[id]!!)
.map { pair: Pair<String, Int> -> func(pair.second) }
Finally, you can make it work without the !! operator by combining the filtering and the mapping in one step using the mapNotNull extension method:
ids.mapNotNull { id: String -> ints[id]?.let { id to it } }
.map { pair: Pair<String, Int> -> func(pair.second) }
This declaration works, but is not the most beautiful code. Is there a way to return functions less ugly? I tried (s: String) -> writer.println(s) but this didn't work.
val writeStuff: (PrintWriter) -> (String) -> Unit = {
val writer = it
val f: (String) -> Unit = {
writer.println(it)
}
f
}
PrintWriter("test").use { writeStuff(it)("TEST") }
EDIT: a bit more concrete example:
val writeStuff: (PrintWriter) -> (String) -> Unit = { writer ->
{ writer.println(it) }
}
val sendStuff: (Any) -> (String) -> Unit = { sender ->
{ sender.equals(it) }
}
#Test fun test1() {
val li = listOf("a", "b", "c")
val process: List<(String) -> Unit> =
listOf(writeStuff(PrintWriter("a")), sendStuff(Object()))
process.map { li.map(it) }
}
First, you can simplify your code using lambda syntax with explicit parameter and inlining val f:
val writeStuff: (PrintWriter) -> (String) -> Unit = { writer ->
{ writer.println(it) }
}
But since Kotlin supports local function declarations, you can even make writeStuff a local fun instead of a val.
This would lead to the following code:
fun writeStuff(writer: PrintWriter): (String) -> Unit {
return { writer.println(it) }
}
Or, using the single expression syntax,
fun writeStuff(writer: PrintWriter): (String) -> Unit = { writer.println(it) }
The usage, however, will be the same:
PrintWriter("...").use { writeStuff(it)("...") }
I stumbled across this question while trying to figure out how to return a Function (the java interface) in Kotlin. While this doesn't directly answer the question, hopefully it'll help someone else who has the same query:
override fun myFun(param1: Object): Function<in Object, out String?> {
if (!param1.meetsCriteria())
return Function { obj -> null }
return Function { obj ->
"success"
}
}
In this case, I was overriding a method in a java interface that required me to return a Function instance. (Note that since the param is not used in my particular implementation above, I could remove it and just have the return result. eg return Function { null })
Edit: After some research, it turns out Kotlin covers this subject with their discussion on "SAM (single abstract method) conversions" here and here, though it may not be the most intuitive thing to look up when figuring out how to return Functions.