-2

Is there a way to properly compare versions? Given the list:

val versionList = listOf("1.0.9", "1.1.9", "2.1.0", "1.1.12");

Is it possible to sort the versions, choose the latest or the earliest ones?

Adam Millerchip
  • 11,422
  • 3
  • 29
  • 48
Sun Mo
  • 27
  • 1

2 Answers2

1

One solution is to use streams with a customize comparator. The custom comparator we can retrieve from this answer on a SO thread:

private static int compare(String v1, String v2) {
    String s1 = normalisedVersion(v1);
    String s2 = normalisedVersion(v2);
    return s1.compareTo(s2);
}

public static String normalisedVersion(String version) {
    return normalisedVersion(version, ".", 4);
}

public static String normalisedVersion(String version, String sep, int maxWidth) {
    String[] split = Pattern.compile(sep, Pattern.LITERAL).split(version);
    StringBuilder sb = new StringBuilder();
    for (String s : split) {
        sb.append(String.format("%" + maxWidth + 's', s));
    }
    return sb.toString();
}

Then used it in a stream:

String latest_version = versionList.stream().max(A::compare).orElse("");

Input:

{"1.0.9","1.1.9","2.1.0","10.1.12"}

Output: 10.1.12

dreamcrash
  • 36,542
  • 23
  • 64
  • 87
1
fun main() {
    val sorted = listOf("1.0.9", "1.1.9", "2.1.0", "1.1.12")
        .map { Version.fromVersionString(it) }
        .sorted()

    println("sorted: $sorted")
    println("earliest: ${sorted.first()}")
    println("latest: ${sorted.last()}")
}

Output:

sorted: [1.0.9, 1.1.9, 1.1.12, 2.1.0]
earliest: 1.0.9
latest: 2.1.0

I wrote the following Version class to help with the above:

data class Version(val major: Int, val minor: Int, val patch: Int) : Comparable<Version> {
    override fun compareTo(other: Version): Int {
        val cmpMajor = major.compareTo(other.major)
        if (cmpMajor != 0) return cmpMajor

        val cmpMinor = minor.compareTo(other.minor)
        if (cmpMinor != 0) return cmpMinor

        return patch.compareTo(other.patch)
    }

    override fun toString() = "$major.$minor.$patch"

    companion object {
        fun fromVersionString(str: String): Version {
            val tokens = str.split(".").map { it.toInt() }
            require(tokens.size == 3) { "Version string is not in x.y.z format." }
            return Version(tokens[0], tokens[1], tokens[2])
        }
    }
}
Adam Millerchip
  • 11,422
  • 3
  • 29
  • 48