So, I am implementing a POM parser. I've got to the point where I can get all dependencies, but some artifacts may be duplicate with different versions. Like gradle, I want it to just fetch the greater version among those. But in kotlin, I can only see examples of removing duplicates using distinctBy function which does not accept a condition. I wanna filter it by only removing the duplicate entry which has the lowest version and keeping the greater one. How can I do so?
The entries in my list is as follows
data class Artifact(val groupId: String, val artifactId: String, val version: String)
edit: For example, let the list be like
Artifact("com.squareup.okio", "okio-jvm", "3.2.0")
Artifact("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", "1.6.20")
Artifact("org.jetbrains.kotlin", "kotlin-stdlib-common", "1.5.20")
Artifact("org.jetbrains.kotlin", "kotlin-stdlib-common", "1.6.21")
Artifact("org.jetbrains", "annotations", "13.0")
And the output is expected to be like
Artifact("com.squareup.okio", "okio-jvm", "3.2.0")
Artifact("org.jetbrains.kotlin", "kotlin-stdlib-jdk8", "1.6.20")
Artifact("org.jetbrains.kotlin", "kotlin-stdlib-common", "1.6.21")
Artifact("org.jetbrains", "annotations", "13.0")
i.e, to remove the version that is the lowest among the duplicates
CodePudding user response:
The main part of this is fairly straightforward: you can use groupBy
to group the artifacts by group ID and artifact ID, and then maxBy
* to select the latest version from each group.
A more tricky part is comparing version strings… But luckily, the Java stdlib⁑ has a class for this!
So you can simply:
import java.lang.module.ModuleDescriptor.Version
data class Artifact(val groupId: String, val artifactId: String, val version: String)
fun main() {
// Some simple sample data:
val deps = listOf(Artifact("gp", "art", "9.2"), Artifact("gp", "art", "9.10"), Artifact("gp", "art", "10.0"), Artifact("gp2", "art2", "1.0"))
// Find the latest version of each dependency:
val latestDeps = deps.groupBy{ it.groupId to it.artifactId }.values
.map{ it.maxBy{ Version.parse(it.version) }}
// And display the result:
println(latestDeps)
}
(That creates a set. Since the items will be unique, but have no inherent ordering, it would make sense to call toSet()
on the result… but I leave that to you!)
(* That's deprecated now in favour of maxByOrNull()
, but I'm ignoring that for simplicity, as the groups here will never be empty.)
(⁑ If you're not running on Kotlin/JVM, then you'll have to write your own version-number-comparing function. I've written one; it's a bit fiddly, but not too hard. — I think you have to split the string on dots and then compare the individual numbers numerically, pairwise, though it's complicated if you have to handle non-numeric parts such as trailing a
or -SNAPSHOT
or patch numbers… If you need to do that, it would probably be best as a separate question.)