In Kotlin get array member with their name like in JavaScripe - kotlin

In Javascript an Array can contain an Object and we can call Object properties by their name.
like
const person = {firstName:"John", lastName:"Doe", age:46};
let fN = person.firstName;
How can achieve this in Kotlin.

You can either try using a mapOf or a custom Person object.
// mapOf
val person = mapOf("firstName" to "John", "lastName" to "Doe", "age" to 46)
val name = person.get("firstName")
print(name) // John
// Custom class
class Person(val firstname: String, val lastname: String, val age: Int)
val person2 = Person(firstname = "John", lastname = "Doe", age = 46)
print(person2.firstname) // John

i think the best way is using data class
data class Person(val firstName:String ,val lastName:String, val age:Int)
val person1 = Person(firstName = "John", lastName = "Doe", age = 46)
val john = person1.firstName //print "John"
//you can use it in a list
val people = listOf(person1,person2,..)
#Edit
data class is kotlin special class with some standard functionality and some utility functions included, such as
equals()/hashCode()
toString() of the form "Person(name=John,lastName="Doe", age=46)"
in normal class when you call println(person1), it will print the memory location of that class, but data class will print your "data"
componentN()
For destructuring like in the javascript
val (firstName,lastNmae,age) = person1
copy()
here is the documentation https://kotlinlang.org/docs/data-classes.html

Related

Why class member property reflection in Kotlin?

In 'Kotlin in Action', it says "if a memberProperty refers to the age property of the Person class, memberProperty.get(person) is a way to dynamically get the value of person.age" with code(10.2.1 The Kotlin Reflection API):
class Peron(val name: String, val age: Int)
>> val person = Person("Alice", 29)
>> val memberProperty = Person::age
>> println(memberProperty.get(person))
29
I can't understand why this example refers to "dynamically" getting the value of property. It just works when I run this code:
println(person.age)
Is there any other case or example of member property reflection?
For example, say you want to write a function which prints all the properties of an object along with their values, this is how you can do that:
inline fun <reified T: Any> T.printProperties() {
T::class.memberProperties.forEach { property ->
println("${property.name} = ${property.get(this)}") // You can't use `this.property` here
}
}
Usage:
data class Person(val firstName: String, val lastName: String)
data class Student(val graduate: Boolean, val rollNumber: Int)
fun main() {
val person = Person("Johnny", "Depp")
val student = Student(false, 12345)
person.printProperties()
student.printProperties()
}
Output:
firstName = Johnny
lastName = Depp
graduate = false
rollNumber = 12345

Sort list in kotlin by variable property given as parameter

I know it's possible to sort a list of person by a property using following syntax:
persons = persons.sortedBy { person: Person-> person.name }
Now i want to write a sort function which accepts the property by which i want the list to be sorted by as an parameter.
In JavaScript i would write something like this:
fun sort(property: String) {
persons = persons.sortedBy { person: Person-> person[property]}
}
But i cannot write "person[property]" in Kotlin.
So how can i achieve such a sorting function in Kotlin?
Now i want to write a sort function which accepts the property by which i want the list to be sorted by as an parameter.
Let's hope that by "the property", you can settle for something like a function reference:
data class Person(val name: String, val age: Int)
var people = listOf(Person("Jane Doe", 25), Person("John Smith", 24), Person("Jen Jones", 37))
fun <R: Comparable<R>> sort(selector: (Person) -> R) {
people = people.sortedBy(selector)
}
fun main() {
println(people)
sort(Person::name)
println(people)
}
I could also use sort(Person::age) if I wanted to sort by age.
If your pseudocode is more literal, and you want a String parameter for the property name, you should start by asking yourself "why?". But, if you feel that you have a legitimate reason to use a String, one approach would be:
data class Person(val name: String, val age: Int)
var people = listOf(Person("Jane Doe", 25), Person("John Smith", 24), Person("Jen Jones", 37))
fun sort(property: String) {
people = when(property) {
"name" -> people.sortedBy(Person::name)
"age" -> people.sortedBy(Person::age)
else -> throw IllegalArgumentException("and this is why you should not be doing this")
}
}
fun main() {
println(people)
sort("name")
println(people)
}
class CustomObject(val customProperty: String, val value:Int)
val list = ArrayList<CustomObject>()
list.add(CustomObject("Z",5))
list.add(CustomObject("A",4))
list.add(CustomObject("B",1))
list.add(CustomObject("X",6))
list.add(CustomObject("Aa",7))
var alphabeticallySortedList = list.sortedWith(compareBy { it.customProperty })
var numberWiseSortedList = list.sortedWith(compareBy { it.value })

Is there a way to generate kotlin dsl using data

We are using kotlin dsl to as a user friendly builder to take input and generate data. Is there a way to do the opposite of that ?
ie, convert existing data into dsl ?
Can this kotlin representation be converted to dsl ?
val person = Person("John", 25)
val person = person {
name = "John"
age = 25
}
Unless you're really crazy about { and some commas, below is an absolutely valid Kotlin code:
data class Person(
val name: String,
val age: Int
)
val person = Person(
name = "John",
age = 25
)
I seems really close to what you want and comes out-of-the-box.
Of course, you can achieve the syntax you want by writing some extra code, like:
import kotlin.properties.Delegates
data class Person(
val name: String,
val age: Int
)
class PersonDSL{
lateinit var name: String
var age: Int by Delegates.notNull<Int>()
fun toPerson(): Person = Person(this.name, this.age)
}
fun person(config: PersonDSL.() -> Unit): Person{
val dsl = PersonDSL()
dsl.config()
return dsl.toPerson()
}
fun main(){
val person = person {
name = "John"
age = 25
}
println(person) // Person(name=John, age=25)
}
But why do that?

What is the easiest way to print a Kotlin data class as compilable code?

I'd like to be able to turn an instance of a fairly simple Kotlin data class into a String that could be copy and pasted into a Kotlin file and would compile.
For example, given these data classes:
data class Parent(val name: String, val age: Int, val children: Set<Child>)
data class Child(val name: String, val age: Int)
I would like a function from any data class to String such that:
toCompilableString(
Parent("Joe", 34, setOf(Child("Amy", 4), Child("Bob", 7)))
)
would return
"""Parent("Joe", 34, setOf(Child("Amy", 4), Child("Bob", 7)))"""
Does such a thing exist?
We can override the behaviour of toString to output in the desired format:
fun main() {
var amy = Child(name="Amy",age=4)
var bob = Child(name="Bob",age=7)
var joe = Parent(name="Joe", age=34, children=setOf(amy, bob))
print(joe) // outputs "Parent("Joe", 34, setOf(Child("Amy", 4), Child("Bob", 7))"
}
data class Parent(val name: String, val age: Int, val children: Set<Child>) {
override fun toString() = "Parent(\"$name\", $age, setOf(${children.joinToString()})"
}
data class Child(val name: String, val age: Int) {
override fun toString() = "Child(\"$name\", $age)"
}
With the help of joinToString(), this will output in the format "Parent("Joe", 34, setOf(Child("Amy", 4), Child("Bob", 7))".
If you really love pain, there are reflection tools made specially for such things. I made a small function that will generate what you need:
fun dataClassToString(instance: Any) {
val sb = StringBuilder()
sb.append("data class ${instance::class.qualifiedName} (")
var prefix = ""
instance::class.memberProperties.forEach{
sb.append(prefix)
prefix = ","
sb.append("${it.name} = ${it.getter.call(instance)}")
}
sb.append(")")
println(sb.toString())
}
The only problem with this function is that for your parent class it generates the following:
data class Parent (age = 34,children = [Child(name=Amy, age=4), Child(name=Bob, age=7)],name = Joe)
Internally set is represented as array, however if you know for sure that you will have only sets or arrays, you can easily check what type it is and append that type when creating the set. You can also check if this is a data class and append it instead of hardcoded string.

Kotlin create object with params syntax

I have an object
class Person {
#JsonProperty("name")
var name: String? = null
#JsonProperty("id")
lateinit var id: String}
There is an only empty constructor and I want to create a person so I wrote:
val person = Person()
person.name = "someName"
person.id = "SomeId"
I'm pretty sure that there is a prettier syntax, something like
val person = Person {name = "someName" , id = "someId"}
but I can't find an example.
am I missing something? should I create a secondary constructor to use this syntax or is there another way?
Please check apply method.
Your code will be like this:
val person = Person().apply {name = "someName", id = "someId"}
Another way - you can change declaration of Person to (e.g. just change brackets, replace var to val and remove lateinit):
class Person (#JsonProperty("name") val name: String? = null,
#JsonProperty("id") val id: String )
Then you will able to do this:
val person = Person(name = "someName", id = "someId")
You can achieve it with the constructor parameter.
class Person(
#JsonProperty("name")
var name: String? = null,
#JsonProperty("id")
var id: String
)
val person = Person(name = "someName", id = "someId")
Another way is make your class and desired variables open to be overridden.
open class Person {
#JsonProperty("name")
open var name: String? = null
#JsonProperty("id")
open var id: String = ""
}
val person = object : Person() {
override var name: String? = "SomeName"
override var id = "SomeId"
}