Remove object from arraylist by property value - kotlin

I have the following problem:
I have a arraylist called "list" which contains objects of the class "SampleClass", the objects have a property "name".
Now I would like to remove a object with a certain "name" value, without knowing the index.
I have tried the following:
list.remove(SampleClass("Village"))
So, the idea would be that the instance of SampleClass where the property name contains "Village" is removed from the list.
It compiles allright, but its not working.

If you want to remove all elements with that name, you can use removeAll:
list.removeAll { it.name == "Village" }
If you only want to remove the first item with that name:
If the name is the only property of the class, you should just make it a data class so equals() is based on the name. Then you could use the code you posted.
If it is not the only property, you will have to get the index in the list and remove it that way:
list.removeAt(list.indexOfFirst { it.name == "Village" })

The way you have it now, you would have to override the equals method in SampleClass to check if the name property is the same. Right now, it probably doesn't work because the default equals method won't compare the name property and so the SampleClass instance you want to remove with that property as "village" will be considered not equal to the SampleClass instance you're passing in.
Otherwise, you can also use list.filter { it.name != "village" }

Related

Collection<KProperty1<I,*>> How to get the property instance

I'm currently using Reflection to inspect an element at runtime using the class.memberProperties function. The type of properties is collection<KProperty1<I, *>> so I run through each of the KProperty objects to find the one that I want by checking if the name is equal to "nameIWant", though I would much rather be able to get the instance of the property from the KProperty by using the .get() method on the property, so that then I could do a check such as:
if (property.get(receiver) is ClassIWant) {
//Do something
}
My code looks like this:
val properties = request.payload::class.memberProperties
properties.forEach { property ->
run {
if (property.name.equals("nameIWant")) {
}
}
}
So far I've been trying to use the .get() method on the KProperty1 type but it takes an argument receiver of type Nothing. I'm not able to work out what I need to pass in order to call the .get() method and get the particular instance of the property. I've also checked the documentation here: https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-property1/index.html but it hasn't really helped at all.
justPassingBy is right. but the more simple way is to use:
myObj.javaClass.kotlin.memberProperties.foreach { property ->
property.get(myObj)
}
If you want to get the value of the property, cast the class into invariant type.
instance::class.memberProperties.first() // returns KProperty1<out Instance, *>
(instance::class as KClass<Instance>).memberProperties.first() // returns KProperty1<Instance, *>
If your KClass<Instance> is KClass<*>, use Any as Instance.
Why did the KProperty.call take Nothing as receiver?
Because instance::class returns KClass<out Instance>, which propagates the covariant type argument down to the property, which it becomes KProperty<out Instance, *>, which narrows down the possible method receiver to any subtype of Instance, but because we do not know which, we can not safely supply any instance of Instance, as show by the rules of variance, which here limit the generic type argument to Nothing, which means it is impossible to call the method at all.
Why is ::class designed to be covariant?
To guarantee safety. This has been an issue of great debates as it seems somewhat illogical.
If you want to know the type of the value that the property can return, use
property.returnType
It returns a KType, wich is Kotlin's version of Java's Type, which is a more generic concept of a Class (which is one of the implementations of Type).
If you need to 'convert' the KType to a KClass, you need to do the same as if you needed to convert Type to a Class, which is get the raw type of the type. Raw type is type stripped of the any generic information, yes, an erased type. The way to do this is (seemingly) more complicated (involves handling each possible KType/Type implementation) and I recommend checking for answer to this problem separately.
You will be able to reuse Java implementation (that you will surely find on your own) using:
kType.javaType.covertJavaTypeToJavaClass().kotlin // returns KClass<*>
Corrections in your question. I recommend using the proper terms if you wish to receive proper answers:
* I in your question is type of the method receiver, not the value of the property
* collection is not a type, Collection is
* property is ClassIWantis ambiguous as property.type is type of the value in the property and property::class is simply the property implementation, is is also an instanceof check, but in reflection, you need to use KClass.isSubclassOf, or what is known in Java as type.isAssignableFrom (watch the call order), which then makes your condition to be ClassIWant.isSuperclassOf(property.type.getRawType())
* instance of the property properties have values, not instances. Only classes have instances. Instances are values and values are instances (of some class), but you must still say instance representing the value of the property
You can create a KType for your ClassIWant and then check the property's returnType. It will be something like this:
val properties = request.payload::class.memberProperties
val desiredType = ClassIWant::class.createType()
properties.forEach { property ->
if (property.name == "nameIWant" && property.returnType == desiredType) {
//todo
}
}
btw you can cast your property variable to correct type and use get
val properties = request.payload::class.memberProperties
properties.forEach { property ->
val value = (property as KProperty1<Payload, *>).get(request.payload)
if (property.name == "nameIWant" && value is ClassIWant) {
//todo
}
}
prop.getter.call(obj) as String?

How to get the name of a variable in Kotlin?

I have a Kotlin class in my application with a lot of attributes, what I want to build is a method that stores the variable name in a dictionary. The dictionary looks like this:
HashMap<String, Pair<Any, Any>>()
The purpose of this is to store the changes made to a certain attribute, I store the name of the variable as the key and in the Pair I store the old value and the new value. To notify a change I use the Observer pattern. So whenever a setter is called from an attribute a change will be notified and stored to the dictionary.
The code below results in the folowing:
var person = Person("Harry", 44)
person.age = 45
HashMap("age", (44, 45))
Right now I am just hardcoding the variable name in as a String, so my question is:
How to dynamicly get the name of a variable in Kotlin?
I saw the same question in Java: Java Reflection: How to get the name of a variable?
Also some other questions about the same topic claiming it is not possible: Get the name property of a variable
I can understand that it is not possible to get the name of a variable, because the compiler simple doesn't have that information, but I am still currious to see if others have any sollution for this problem.
As stated in the Kotlin documentation about Reflection:
val x = 1
fun main() {
println(::x.get())
println(::x.name)
}
The expression ::x evaluates to a property object of type KProperty<Int>, which allows us to read its value using get() or retrieve the property name using the name property.
Use memberProperties to get the names of the class attributes and others properties. For instance:
YourClass::class.memberProperties.map {
println(it.name)
println(it.returnType)
}
I think delegate properties is the solution to my problem:
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
Credits go to: Roland
Source: https://kotlinlang.org/docs/reference/delegated-properties.html

copy one arraylist to another arraylist in kotlin

I am trying to copy one ArrayList to another ArrayList in Kotlin
1st ArrayList:
private var leadList1: ArrayList<Lead> = ArrayList()
2nd ArrayList:
val leadList2: ArrayList<Lead?>?
I tried to use addAll(). leadList1.addAll(leadList2)
But its not working.
Error showing:
Required: Collection<Lead>
Found: kotlin.collections.ArrayList<Lead?>?
This isn't safe to do, because your first list can only contain objects of type Lead, while your second one has Lead? as its type parameter, meaning that it might contain null values. You can't add those to the first list.
The solution for this problem will depend on your context, but you can either let the first list contain nullable elements too:
private var leadList1: ArrayList<Lead?> = ArrayList()
Or you can add only the non-null elements of the second list to the first one:
leadList1.addAll(leadList2.filterNotNull())
And in either case, you'll have to perform a null check on leadList2, because the entire list itself is marked as potentially null as well, signified by the last ? of the type ArrayList<Lead?>?.
if (leadList2 != null) {
leadList1.addAll(leadList2.filterNotNull())
}
You can simply pass another List instance into the constructor of your new List
val originalList = arrayListOf(1,2,3,4,5)
val orginalListCopy = ArrayList(originalList)
Do this:
leadList1.addAll(leadList2.orEmpty().filterNotNull())
And to filter by property you can do like this:
leadList1.addAll(leadList2.orEmpty().filter { item -> item?.type == YourTypeString })

Why do I need a parameter in a primary constructor without val/var modifier in Kotlin?

If I create a class, I can pass a parameter:
class Person(name: String) {
}
I also can write the same, but with val and then I'll be able to use properties to get this value, when I created an object.
val person = Person("Name")
person.name
The question is: why do I need just a parameter without the val? Where, how and why should I use it?
If you use varor val in the constructor, you are declaring properties and initializing them directly. If you don't, those parameters are used for initialization purposes:
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
https://kotlinlang.org/docs/reference/classes.html
It's used when you don't want constructor arguments to become named properties on the class.
If you use val, you get a read-only property. If you use var, you get a mutable property. Otherwise, you get nothing [auto-defined].

Cocoa Bindings and Checking for String content

OK, here's what I want to do :
Let's say I have an item, e.g. an NSTextField
Let's also say we want to bind its hidden value to a BOOL variable - that's easy.
Now, here's the twist :
I want to bind the hidden property to a check in the fashion of (someStringVariable == "Some String")
In a few words : set the element to hidden when someStringVariable is equal to some string.
How can I do that from within the IB? Is it doable?
Well, this is basically a duplicate of this question which I answered. But somebody other than the questioner has put a bounty on this one, so:
Entirely within IB? No.
You can bind to a string-typed property and then use a custom value transformer to convert that string to a boolean according to its equality to the desired value.
However, it's probably just easier to add a property to the class that has the string-typed property:
// Assumed to exist:
#property (copy) NSString* someStringProperty;
+ (NSSet*) keyPathsForValuesAffectingShouldBeHidden
{
return [NSSet setWithObject:#"someStringProperty"];
}
- (BOOL) shouldBeHidden
{
return [self.someStringProperty isEqualToString:#"desired string"];
}
Since this property is really part of the UI rather than the model, you may wish to define it in a category on the model class. The category itself would be declared and defined in the controller code.
Once it's defined, you can bind to the shouldBeHidden property.
You mean someting like this?
string1=string2 ? hidden=true : hidden=false