バージョン番号のソートが流行っているようなので、Kotlin でやってみた1。
元ネタ:「アルゴリズムのせいで面接に落ちた」
/**
* バージョン番号を表す文字列を比較する [Comparator]。
*
* バージョン番号は数値を `.` で区切ったもの。
*/
class VersionComparator : Comparator<String> {
override fun compare(a: String, b: String): Int {
if (a == b) return 0
val numberListA = a.toNumberList()
val numberListB = b.toNumberList()
return (numberListA zip numberListB)
.find { (numberA, numberB) ->
numberA != numberB
}
?.let { (numberA, numberB) ->
numberA.compareTo(numberB)
}
?: numberListA.size
.compareTo(
numberListB.size
)
}
companion object {
private fun String.toNumberList(): List<Int> =
split(".").map { it.toInt() }
}
}
記事「[JavaScript] Version のソートアルゴリズムを高階関数縛りで考えてみた」を参考にさせていただいた。
バージョン番号に数字以外が入ってくる場合については考えていない(実行時例外がスローされる)。
パターンがありすぎてきりがない(その都度 Comparator
を実装した方がよい)ため。
動作確認。
fun main() {
// ソートする対象。
val versions = listOf(
"1.3.0.9",
"0.2.0",
"3.1.2",
"0.1.6",
"5.0.0",
"3.3.3.3",
"3.3.3.3.3",
"3.10",
"0.2.0",
)
// 期待されるソート結果。
val output = listOf(
"5.0.0",
"3.10",
"3.3.3.3.3",
"3.3.3.3",
"3.1.2",
"1.3.0.9",
"0.2.0",
"0.2.0",
"0.1.6",
)
versions.sortedWith(
VersionComparator()
.reversed() // 降順にする。
).also {
println(it == output) // > true
}
}
-
というか Kotlin 以外めんどくさくて書きたくない。 ↩