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?
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?
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
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])
}
}
}