Kotlin Map with If statement - kotlin

Trying to write some Functional code and use map - maybe filter too? - to replace something like:
for (something in somethingList) {
if (something.value == someOtherThing.value)
result = true
}
With something more functional like found here: https://grokonez.com/kotlin/kotlin-filter-map-examples
But I don't want to return a new map I want to set result to the condition of something.value == someOtherThing.value being true or not.
But I'm getting lost in my neophyte world of Functional Kotlin.
Can anyone nudge me in the right direction?
Thanks

You can use any for this purpose.
val result = somethingList.any { it.value == someOtherThing.value }

Related

Kotlin: mark function argument after sanitizing it into a new variable as "do not use this anymore"

To start: this question is already kind of resolved for me. But the discussion might be interesting.
I like code so let's look at this function:
fun foo(path: Path) {
val absPath = path.normalize().absolute() // sanitizing
doSomethingWith(path) // this is unsafe use because path is not sanitized
doSomethingWith(absPath) // this is safe because we are using the sanitized absPath value
}
Kotlin function parameters are always val, therefore we are required to create a new variable if we want to derive from it's value.
We can choose between using a new name or using an old name and annotating it with #Suppress("NAME_SHADOWING") to not get the Name shadowed: ... warning.
I'm looking for something like
fun foo(path: Path) {
val absPath = path.normalize().absolute()
#DoNotUseAnymore path
doSomethingWith(path) // should give a warning/error
doSomethingWith(absPath) // is fine
}
Do you know something like that? Or do you think I'm fiddling around at the wrong end of the equation and should just learn to not feel like doing bad stuff when using the #Suppress-annotation? Since I like to code, this is what I mean:
fun foo(path: Path) {
#Suppress("NAME_SHADOWING")
val path = path.normalize().absolute() // sanitizing
doSomethingWith(path) // there is only one sanitized variable so we are safe
}
In some way this method is the cleanest one... I probably stick to that... Should I publish this question now? Well... maybe :)

refactor if to takeIf and return "return" without label kotlin

I am trying to write more idiomatic Kotlin code and I am stuck with the best way to refactor this if condition. Basically when the condition if true (fragment is GenericActionsBottomSheetDialog instance in a list of Fragments) I return the funcion itself.
Here is what I had and how I refactored it. Is there better way to achieve it? After my refactoring it get worse:
Before refactor:
supportFragmentManager.fragments.iterator().forEach {
if (it is GenericActionsBottomSheetDialog)
return
After refactor:
supportFragmentManager.fragments.iterator().forEach { it ->
it.apply {
takeIf { it is GenericActionsBottomSheetDialog }?.apply { return }}}
If this forEach is the only thing in your current function (which it should IMO), you could get rid of the non-local return by using takeWhile instead:
supportFragmentManager.fragments
.takeWhile { it !is GenericActionsBottomSheetDialog }
.forEach {
// do stuff
}
/!\ be careful that this changes semantics if there is other stuff after the forEach in the same function declared with fun.
If you expect many fragments in the list, you could also use asSequence() before takeWhile so you don't create an intermediate list.
Here's one possibility, which separates the decision from the action:
if (supportFragmentManager.fragments.any{ it is GenericActionsBottomSheetDialog })
return
I think this approach makes the intent clearest. (It's also about the most efficient.)
any() simply checks each item in turn, stopping when it finds a match (or when it reaches the end of the list). Kotlin has many functions like this (inspired by functional programming languages) that use lambdas to operate on lists and other structures. They tend to be named for what they do, rather than how they do it — which makes code using them both short and easy to read. (You should be writing code for people to read, as much as for computers to execute!)
For completeness, here's another approach, which uses filterIsInstance():
if (supportFragmentManager.fragments
.filterIsInstance<GenericActionsBottomSheetDialog>)
.isNotEmpty())
return
There are bound to be many other ways. But I agree with the commenter that your ‘refactored’ approach, while using many more Kotlin functions, has little else to recommend it!
This is an opinion based question, and answers cannot be any different.
That being said: there is nothing wrong with if clauses. From what I can see from your current question, I'd leave it with an if.
Now, if you really do not want to use it, filter elements that are not of type GenericActionsBottomSheetDialog and apply whatever function you want on them (the part that is in your else clause, which we do not see).
EDIT:
In case you only want to check if the object of the GenericActionsBottomSheetDialog exists in the collection, you can perhaps do it like this:
val dialogExists = supportFragmentManager.fragments
.firstOrNull { it is GenericActionsBottomSheetDialog} != null
if (dialogExists) {
return
}
#gidds solution is IMO the most idiomatic one:
if (supportFragmentManager.fragments
.any { it is GenericActionsBottomSheetDialog }) return
I would like to add this solution eliminating the if:
supportFragmentManager.fragments
.firstOrNull { it is GenericActionsBottomSheetDialog }
?.run { return }
It's a matter of taste which one you pick, I prefer the first one.
I was wondering why you use the iterator? You could simply do:
supportFragmentManager.fragments.forEach {

Pass no value to function with default parameters

I have this Kotlin function:
fun doSomething(user: User = defaultUser) {
//do something
}
and I call it from another place:
val user: User? = getUser()
if (user == null) {
doSomething()
} else {
doSomething(user)
}
Is it possible to improve this code? I think this "if/else" is a little bit messy. Is possible to do something like this?
doSomething(user ?: NoValue)
You can cut it down to user?.run(::doSomething) ?: doSomething() (if doSomething doesn't return null) but I don't know why you'd want to!
Honestly the if/else reads nice to me, stick it on one line without the braces and it's nice and compact. Unfortunately I don't think you can conditionally add parameters into a function call (and handling default parameters can get unnwieldy when you have a few).
I agree with #benjiii, it might be better to have a nullable parameter and handle the default internally, if you don't need to use null as a legit value
You could do something like this:
getUser()?.let { // user is not null
doSomething(it)
} ?: run { // user is null here
doSomething()
}
(cf: Swift 'if let' statement equivalent in Kotlin)
I don't think you could do something shorter without making the code hard to understand Edit 2: Actually you can, see the comment
Edit: I would personally handle the nullable variable inside the function like this:
fun doSomething(user: User?) {
val correctUser = user ?: defaultUser
//do something
}
so you can use the function like this:
doSomething(getUser())
I agree with cactustictacs, just putting it on one line is clear and simple. However, if you use it often and it's bothering you, it's easy enough to wrap it in a function without the default parameter:
fun doSomethingSensibly(user: User?) =
if (user == null)
doSomething()
else
doSomething(user)
Which can be used as:
doSomethingSensibly(getUser())

Option Chaining instead of if/else

Is there a more succint way to write the following code using option chaining and/or the elvis operator?
email.addSubject(if (creator != null) String.format( inviteDescription, creator) else String.format(inviteDescriptionNoCreator, group))
It feels like there should be.
Using the normal IF expression
val subject = if (creator != null) {
inviteDescription.format(creator)
} else {
inviteDescriptionNoCreator.format(group)
}
email.addSubject(subject)
The Elvis Operator
val subject = creator?.let {
inviteDescription.format(it)
} ?: inviteDescriptionNoCreator.format(group)
email.addSubject(subject)
If the goal is to write the shortest code possible then you could go with a single line Elvis operator. But if the goal is a readable code, I would choose the simple if expression or a multi line Elvis operator. I would even go one step ahead and move it to a separate method. But whatever you choose, please don't write everything in a single long line, rather put it in separate lines.
Just taking advantage of ?. and ?: gives us the following:
email.addSubject(creator?.let { String.format(inviteDescription, it) } ?: String.format(inviteDescriptionNoCreator, group))
Unfortunately, that's still quite long and is arguably not much easier to read. You could shave off a bit more by using the String.format extension function:
email.addSubject(creator?.let { inviteDescription.format(it) } ?: inviteDescriptionNoCreator.format(group))

Why .map on a mutableList doesn't actually change values inside of List in Kotlin?

This is what I have and what I want to achieve:
I have a class which has a mutableList as a field.
I want to find a specific element inside that list and change it.
This is what I've tried so far:
This is the functional statement I was hoping would have worked, after I've also put it in an Extension function:
fun Classroom.setNewParameters(id: String, modifiedName: String) {
this.students.filter { l -> l.id == id }
.map { l -> l.name = modifiedName }
.toList()
}
But the list students appears to be unchanged after this function is called.
I found an "ugly" solution with the code below:
fun Classroom.setNewParameters(id: String, modifiedName: String) {
for (l : Student in this.students) {
if (l.id == id) {
l.name = modifiedName
break
}
}
}
Still tho, I'd really like to know why the first block of code behaves like it does and doesn't actually have any effect on the list.
You can think of map as a way to transform input to get new output. Normally it should not mutate state inside, in other words it should be a function without side effects to pursue maintainability
In your case you clearly want to mutate elements, for that you might want to use that code snippet:
fun Classroom.setNewParameters(id: String, modifiedName: String) {
this.students.filter { l -> l.id == id }
.onEach { l -> l.name = modifiedName }
}
Also, even you used map incorrectly it should must modify field l.name (unless you have implemented you own delegates or getter/setter). Try to debug set breakpoint on this.students.filter { l -> l.id == id } and see if there are any items left after filtering
Noob here but I did just see something related to this the other day.
Is there a reason you wouldn't just check to see if your array contains the old value, return the element id and then assign your new value to that id?
I guess I'm just pointing out that this could be accomplished with a "value in array" type search... but I'm still too new to know the pros and cons of using it vs map.
Kind of like this below, which I got from Kotlin - Idiomatic way to check array contains value
"value" in array
Which translates into the Java API:
array.contains("value")
So I'd check for the old value in the array, return it's index and then reassign that index with the new value.