David Kubecka
03/24/2023, 9:55 AMval (xs, nonXs) = list.partition { it is X }
// xs is of type List<X>
Wout Werkman
03/24/2023, 9:56 AMDavid Kubecka
03/24/2023, 9:59 AMWout Werkman
03/24/2023, 10:02 AMDavid Kubecka
03/24/2023, 10:06 AMStephan Schröder
03/24/2023, 2:30 PMinline fun <A,reified B: A> List<A>.partitionIsInstance(): Pair<List<A>, List<B>> {
val aList = ArrayList<A>(this.size)
val bList = ArrayList<B>(this.size)
this.forEach {
if (it is B) {
bList.add(it)
} else {
aList.add(it)
}
}
return aList to bList
}
unfortunately, the compiler isn't smart enough to deduce the types correctly from
val instances: List<AC> = listOf(AC(), AC(), BC(), AC(), BC() )
val (aList: List<AC>, bList: List<BC>) = instances.partitionIsInstance()
so you have to add the types to the invocation:
val (aList: List<AC>, bList: List<BC>) = instances.partitionIsInstance<AC, BC>()
here's the playground link to play around with it: https://pl.kotl.in/RDbthQSqOJoffrey
03/24/2023, 2:33 PMfilterIsInstance<X>()
twice. But if you need this more often, something like what Stephan suggested would indeed be betterpartition
returns first the true elements and then the false onesStephan Schröder
03/24/2023, 2:43 PMinline fun <A,reified B: A> MutableList<A>.extractSubclass(): List<B> {
val bList = ArrayList<B>(this.size)
this.forEach {
if (it is B) {
bList.add(it)
}
}
this.removeAll(bList)
return bList
}
afterwards your initial list only has the instances which weren't the specific subclass. Also type inference is smarter now:
val instances: MutableList<AC> = mutableListOf(AC(), AC(), BC(), AC(), BC() )
val bList: List<BC> = instances.extractSubclass()
try it out here: https://pl.kotl.in/EflE6GJPZisInstance
😅
inline fun <A,reified B: A> MutableList<A>.extractSubclass(): List<B> {
val bList = this.filterIsInstance<B>()
this.removeAll(bList)
return bList
}
David Kubecka
03/24/2023, 2:48 PMyou could also useYeah, that's actually what I'm currently doing. But the explicit cast (especially if nicely encapsulated) is IMO worth the peace of mind that single pass algorithm provides 😅twice.filterIsInstance<X>()
Stephan Schröder
03/24/2023, 2:51 PMinline fun <A,reified B: A> MutableList<A>.extractSubclass(): List<B> = this.filterIsInstance<B>().also {this.removeAll(it)}
David Kubecka
03/24/2023, 2:55 PMinstances.partitionIsInstance<AC, BC>()
. The AC
can be derived from the context (instances
) so I would rather want it to be used as instances.partitionIsInstance<BC>()
. The ease of use is probably my main acceptance criterion for such a utility function.Stephan Schröder
03/24/2023, 2:57 PMAC
part, not even in 1.8.20-RC.
I was slightly disappointed as well.David Kubecka
03/24/2023, 3:01 PMfun <T> List<T>.first(...)
it has trouble doing so partially for more params.
Do you think this is worth reporting? Or perhaps it's already reported?Stephan Schröder
03/24/2023, 3:02 PMval aList = ArrayList<A>(this.size/2)
val bList = ArrayList<B>(this.size/2)
Not something I normally thing about in a GC-language 😅David Kubecka
03/24/2023, 3:07 PMWout Werkman
03/24/2023, 3:12 PMephemient
03/24/2023, 6:17 PMinline fun <T, R : Any> Iterable<T>.mapNotNullAndPartition(transform: (T) -> R?): Pair<List<R>, List<T>> {
val mapped = mutableListOf<R>()
val unmapped = mutableListOf<T>()
for (elem in this) {
transform(elem)?.let { mapped.add(it) } ?: unmapped.add(elem)
}
return mapped to unmapped
}
val (xs, nonXs) = list.mapNotNullAndPartition { it as? X }
if this is a recurring patternDavid Kubecka
03/24/2023, 7:31 PMephemient
03/24/2023, 7:33 PM.mapNotNullAndPartition { it.toIntOrNull() }
for exampleDavid Kubecka
03/24/2023, 7:37 PMinline fun <A,reified B: A> List<A>.partitionIsInstance()
and a concrete call List<Int>.partitionIsInstance()
there's no way that the compiler could infer that A is Int?ephemient
03/24/2023, 7:38 PMpartition
function taking a predicateDavid Kubecka
03/24/2023, 7:38 PM