https://kotlinlang.org logo
#getting-started
Title
# getting-started
m

Manuel Dossinger

11/16/2021, 2:00 PM
if I have a List<T?> and want to filter elements such that I have a List<T> without null values and such that they satisfy a certain predicate, i could do
myList.filterNotNull().filter { f(it) }
, but that would essentially loop through the list twice, correct?
j

Joffrey

11/16/2021, 2:01 PM
Yes, and not only loop twice but it will also create a whole intermediate
List
after the
filterNotNull
.
Usually it's not that big of a deal. But if you have very big collections or if you're measuring that this is a bottleneck for some reason, you can convert your list to a sequence in order to mitigate this. Or you can just use a single
filter
but that will not make the type of the elements non-null, which is annoying
m

Manuel Dossinger

11/16/2021, 2:03 PM
So if I don't want that overhead, I need to do something like
filter { it != null && predicate(it) }
but I need to cast that to List<T>, because the compiler thinks it is still a List<T?>
j

Joffrey

11/16/2021, 2:05 PM
Yeah I guess we wrote at the same time 🙂 This is what I meant in my last option, yes. The first option would be to just be OK with the extra iteration/collection (seriously it might not be a problem at all). The second option would be using a sequence:
Copy code
myList.asSequence().filterNotNull().filter { predicate(it) }.toList()
Note that in general I extremely rarely encounter lists of nullable items. Maybe there is something you can do up front to avoid the nullable items in the first place?
m

Manuel Dossinger

11/16/2021, 2:09 PM
I guess the sequence idea is best for my case; I don't think I can get rid of the nullable items unfortunately
Thanks a lot 🙂
j

Joffrey

11/16/2021, 2:11 PM
What collection sizes do you expect to handle here? Because your initial code might be OK
m

Manuel Dossinger

11/16/2021, 2:12 PM
Its in a frameworky part of the codebase and rather generic, so I do neither know if the collections are large nor if the filtering is done in a tight loop
👌 1
m

mkrussel

11/16/2021, 2:23 PM
You could always create your own method that does this. Look at the implementation of
filter
and
filterNotNull
, I don't think they are complicated.
👍 1
j

Joffrey

11/16/2021, 2:25 PM
That's a fair point
j

Jacob

11/16/2021, 3:22 PM
Keep in mind, The difference between sequence and list here is minimal. There both going to run in O(n).
j

Joffrey

11/16/2021, 3:26 PM
@Jacob Asymptotic execution time behaviour is not always the only thing that matters. Iterating once or 100 times over a given list can be a significant difference if it's big, and yet both are O(n). Creating an intermediate array list of 2M elements after the first
filterNotNull
might also be a significant difference. It's all about context / use case.
👍 2
m

Manuel Dossinger

11/16/2021, 5:06 PM
@mkrussel They are really very readable, in fact, I started writing such an implementation before coming to this channel 🙂
e

ephemient

11/16/2021, 9:45 PM
Copy code
myList.mapNotNull { if (it != null && f(it)) it else null }
a little contrivance results in a
List<T>
in a single pass, thanks to smart casting
m

mkrussel

11/16/2021, 9:49 PM
myList.mapNotNull { it?.takeIf(f) }
👍 2
I think something like that would work.
e

ephemient

11/16/2021, 9:52 PM
either
f
or
::f
depending on context, but yes, that's equivalent
2 Views