Home > Enterprise >  Remove duplicate entry from list with a condition in kotlin
Remove duplicate entry from list with a condition in kotlin

Time:12-24

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.)

  • Related