I want to write a kotlin function that can filter lists.
The filtering I want to do is pretty much an ID whitelisting, so imagine that I have a list of string IDs that are allowed. Then the function should remove all objects of the input list that have an ID not in the whitelist. Pretty basic stuff really.
The problem I guess is that I want it really generic. And I am wondering if it is possible in kotlin to take in a list of Any, but that have a property id?
Or is it only possible by creating an interface that all objects need to implement?
fun <T> List<T>.filterUnknownIds(getId: T.() -> String): List<T> = filter { it.getId() in whitelistedIds }
Assuming whitelistedIds is a list of strings. I didn't compile the code as I'm on mobile but should work.
Related
I wonder if a data class with one of the properties being a function, such as:
data class Holder(val x: Data, val f: () -> Unit)
can work at all, since the following test fails.
val a = {}
val b = {}
Assert.assertEquals(a, b)
Update: Use case for this could be to have a
data class ButtonDescriptor(val text: String, val onClick: () -> Unit)
and then flow it to UI whilst doing distinctUntilChanged()
I don't think this is possible, I'm afraid.
You can of course check reference equality (===, or == in this case because functions don't generally override equals()). That would give you a definite answer where you have references to the same function instance. But that doesn't check structural equality, and so reports the two lambdas in the question as different.
You can check whether the two functions are instances of the same class by checking their .javaClass property. If the same, that would imply that they do the same processing — though I think they could still have different variables/captures. However, if different, that wouldn't tell you anything. Even the simple examples in the question are different classes…
And of course, you can't check them as ‘black boxes’ — it's not feasible to try every possible input and check their outputs. (Even assuming they were pure functions with no side effects, which in general isn't true!)
You might be able to get their bytecode from a classloader, and compare that, but I really wouldn't recommend it — it'd be a lot of unnecessary work, you'd have to allow for the difference in class names etc., it would probably have a lot of false negatives, and again I think it could return the same code for two functions which behaved differently due to different parameters/captures.
So no, I don't think this is possible in JVM languages.
What are you trying to achieve with this, and could there be another way? (For example, if these functions are under your control, can you arrange for reference equality to do what you need? Or could you use function objects with an extra property giving an ID or something else you could compare?)
When you create your data class, if you pass the function by reference it will work with DiffUtils and distinctUntilChanged(). Function references do not break the isEquals() method of data classes in the same way that a lambda does.
For example, you create a function for your onClick:
private fun onClick() { // handle click }
and create your data class like
BottomDescriptor("some text", ::onClick)
I am trying to find better way to chain the filter and map operators in Kotlin. What I want to do is to filter the null items before going to the map operator.
I was able to chain them, but the compiler complained about the nullability of my list items.
class Person(val age : String?)
fun foo(age :String){
// require non-null age
}
The sample usage was:
val list = mutableListOf(Person("3"), Person("2"))
list.filter{ it.age != null }.map{ foo(it.age) }
// The IDE wants me to add !!
So why can't Kotlin infer the nullability? The filtered (all non-null) items passed down to map should had been filtered to ensure that they are non-null.
You can replace filter and map with one method mapNotNull:
val list2 = list.mapNotNull { it.age }
This case may seem easy for a human, but technically speaking it would be really hard for the compiler to understand that after filtering it is a list of people objects, but with different type of the age property than original.
If you don't use a whole people instance at map() stage then I think the easiest would be to do:
list
.mapNotNull { it.age }
.map(::foo)
Or, if your foo() can't return nulls:
list.mapNotNull { it.age?.let(::foo) }
But I think this is less readable. Or you can just use !! - it's not that bad if we know what we're doing.
You can use the Iterable<T>.filterNotNull() extension function here which will return a list of the non-nullable type.
In your case, the compiler just isn't advanced enough to smart-cast the filtered list, it would be quite a lot to ask. So if you need to use filter specifically you would have to add an assertion.
I learned java and python in high school and I became very comfortable with python. I have recently started to learn kotlin, mainly for fun (the keyword for defining a function is fun so it has to be a fun language, right), but I have a little problem.
Let's suppose I have a hierarchy of classes for Chess pieces:
abstract class Piece {
...
}
class Rook : Piece() {
...
}
class Bishop : Piece() {
...
}
.
.
.
I am taking input from the user to generate the board, so if the user types r, I need to create a Rook object, if he types b, I need to create a Bishop etc.
In python, I'd probably use a dictionary that maps the input string to the corresponding class, so I can create an object of the correct type:
class Piece:
...
class Rook(Piece):
...
class Bishop(Piece):
...
.
.
.
input_map = {
'r': Rook,
'b': Bishop,
...
}
s = input_map[input()]() # use user input as key and create a piece of the correct type
I was really amazed by this pattern when I discovered it. In java, I had to use a switch case or a bunch of if else if to achieve the same result, which is not the end of the world, especially if I abstract it into a separate function, but it's not as nice as the python approach.
I want to do the same thing in kotlin, and I was wondering if there is a similar pattern for kotlin since it's a modern language like python (I know, I know, python isn't new, but I think it's very modern). I tried to look online, but it seems like I can't store a class (class, not an object) in a variable or a map like I can in python.
Am I wrong about it? Can I use a similar pattern in kotlin or do I have to fall back to the when statement (or expression)?
If I am not mistaken, a similar pattern could be achieved in java using reflection. I never got to learn reflection in java deeply, but I know it's a way to use classes dynamically, what I can do for free in python. I also heard that in java, reflection should be used as a last resort because it's inefficient and it's considered "black magic" if you understand my meaning. Does it mean that I need to use reflection to achieve that result in kotlin? And if so, is it recommended to use reflection in kotlin, and is it efficient?
I'd like to know how I can approach this problem, and I accept multiple answers and additional solutions I didn't come up with. Thanks in advance.
This can be done without reflection.
You can map the input characters to the constructors:
val pieceConstructorsByKeyChar = mapOf(
'r' to ::Rook,
'b' to ::Bishop,
// etc.
)
Getting values from a map gives you a nullable, since it's possible the key you supply isn't in the map. Maybe this is fine, if when you use this you might be passing a character the player typed that might not be supported. Then you would probably handle null by telling the player to try again:
val piece: Piece? = pieceConstructorsByKeyChar[keyPressed]?.invoke()
Or if you do the look-up after you've already checked that it's a valid key-stroke, you can use !! safely:
val piece: Piece = pieceConstructorsByKeyChar[keyPressed]!!()
Yes you can use similiar approach with Kotlin. Kotlin has many features and supports reflection. Let me write an example about your problem.
Firstly create your classes that will be generate by user input.
abstract class Piece
class Rook : Piece()
class Bishop : Piece()
Create your class map
val inputMap = mapOf(
"r" to Rook::class.java,
"b" to Bishop::class.java
)
Create an instance what you want using newInstance function. If your input map doesn't contains key you gave then it will return null.
val rook = inputMap["r"]?.newInstance()
val bishop = inputMap["b"]?.newInstance()
// null
val king = inputMap["k"]?.newInstance()
Also you can write your custom extensions to create new objects.
fun <T> Map<String, Class<out T>>.newInstance(key: String) = this[key]?.newInstance()
// Create an instance with extension function
inputMap.newInstance("r")
New to Kotlin. I was thinking if there is a shorter way to write the following piece of code. It means to categorize enum values into a multi-value map.
fun androidPermissionsByCategory(): Map<String, List<String>> {
val result = hashMapOf<String, MutableList<String>>()
enumValues<AndroidPermission>().onEach {
result.getOrPut(it.permissionGroup, { mutableListOf() }).add(it.value())
}
return result
}
Suggestions?
That's good, solid code (especially if you're not experienced in Kotlin): good use of types, and the getOrPut() function. (The only tweak I'd suggest would be to change hashMapOf() to mutableMapOf(), since you don't care about the exact type of map. You could also replace the add() call with += operator, though that's more disputable.)
However, there's a shorter alternative in a more functional style:
fun androidPermissionsByCategory(): Map<String, List<String>>
= enumValues<AndroidPermission>()
.groupBy({ it.permissionGroup }, { it.value() })
(Disclaimer: I don't have Android libs, so I can't test this exactly.)
This uses the standard library's groupBy() function, which does exactly what you want: it compares items (using a key-selector lambda you provide), and uses it to create a multimap from them.
Here we're using the enum's permissionGroup field as the key.
We're also using the optional second parameter to transform the values in the multimap, in this case getting their value().
You'll find that Kotlin has functional alternatives to many of the common imperative patterns for constructing and transforming maps, lists, and similar structures; these are often more concise, more declarative, and easier to read. Any time you find yourself looping over a list or similar, it's worth asking whether there's a better way. (As you have here! Your intuition is clearly working well :-)
I asked a question at How to design a complex class which incude some classes to make expansion easily in future in Kotlin? about how to design a complex class which incude some classes to make expansion easily in future in Kotlin.
A expert named s1m0nw1 give me a great answer as the following code.
But I don't know why he want to change MutableList to List at https://stackoverflow.com/posts/47960036/revisions , I can get the correct result when I use MutableList. Could you tell me?
The code
interface DeviceDef
data class BluetoothDef(val Status: Boolean = false) : DeviceDef
data class WiFiDef(val Name: String, val Status: Boolean = false) : DeviceDef
data class ScreenDef(val Name: String, val size: Long) : DeviceDef
class MDetail(val _id: Long, val devices: List<DeviceDef>) {
inline fun <reified T> getDevice(): T {
return devices.filterIsInstance(T::class.java).first()
}
}
Added
I think that mutableListOf<DeviceDef> is better than ListOf<DeviceDef> in order to extend in future.
I can use aMutableList.add() function to extend when I append new element of mutableListOf<DeviceDef>.
If I use ListOf<DeviceDef>, I have to construct it with listOf(mBluetoothDef1, mWiFiDef1, //mOther), it's not good. Right?
var aMutableList= mutableListOf<DeviceDef>()
var mBluetoothDef1= BluetoothDef(true)
var mWiFiDef1= WiFiHelper(this).getWiFiDefFromSystem()
aMutableList.add(mBluetoothDef1)
aMutableList.add(mWiFiDef1)
// aMutableList.add(mOther) //This is extension
var aMDetail1= MDetail(myID, aMutableList)
Sorry for not giving an explanation in the first place. The differences are explained in the docs.:
Unlike many languages, Kotlin distinguishes between mutable and immutable collections (lists, sets, maps, etc). Precise control over exactly when collections can be edited is useful for eliminating bugs, and for designing good APIs.
It is important to understand up front the difference between a read-only view of a mutable collection, and an actually immutable collection. Both are easy to create, but the type system doesn't express the difference, so keeping track of that (if it's relevant) is up to you.
The Kotlin List<out T> type is an interface that provides read-only operations like size, get and so on. Like in Java, it inherits from Collection<T> and that in turn inherits from Iterable<T>. Methods that change the list are added by the MutableList<T> interface. [...]
The List interface provides a read-only view so that you cannot e.g add new elements to the list which has many advantages for instance in multithreaded environments. There may be situations in which you will use MutableList instead.
I also recommend the following discussion:
Kotlin and Immutable Collections?
EDIT (added content):
You can do this is a one-liner without any add invocation:
val list = listOf(mBluetoothDef1, mWiFiDef1)