Давайте розглянемо, як задачу https://leetcode.com/problems/relative-ranks/solutions/6326961/sorting-mapping-approach можна вирішити трьома мовами програмування — Java, Kotlin та Scala.
Проблема: Знаходимо відносні ранги
Маючи масив балів (int[] score), необхідно присвоїти ранги, як-от "Золота медаль", "Срібна медаль" та "Бронзова медаль" для трьох найкращих, а іншим гравцям — числовий ранг. Основна мета — написати оптимальний і зрозумілий код.
Рішення на Java: Класика, потужність, боілерплейт
class Solution {
public String[] findRelativeRanks(int[] score) {
int[] sorted =
Arrays.stream(score)
.boxed()
.sorted(Collections.reverseOrder())
.mapToInt(Integer::intValue)
.toArray();
Map<Integer, Integer> rankMap = new HashMap<>();
for (int i = 0; i < sorted.length; i++) {
rankMap.put(sorted[i], i);
}
return Arrays.stream(score)
.mapToObj(individualScore -> {
int rank = rankMap.get(individualScore);
return switch (rank) {
case 0 -> "Gold Medal";
case 1 -> "Silver Medal";
case 2 -> "Bronze Medal";
default -> String.valueOf(rank + 1);
};
})
.toArray(String[]::new);
}
}
Java може здатися дещо громіздкою, особливо для роботи з колекціями.
Другий пункт коду, де ми створюємо rankMap
, реалізований у імперативному стилі. Java, на жаль, не має синтаксичних конструкцій, які дозволили б виразно та читабельно написати цю частину декларативно. Тому я обрав імперативний підхід, щоб забезпечити чіткість та простоту логіки.
Рішення на Kotlin: Сучасний підхід
class Solution {
fun findRelativeRanks(score: IntArray): Array<String> {
val rankMap =
score.sortedArrayDescending()
.withIndex()
.associate { (index, value) -> value to index }
return score.map { mapScoreToRank(it, rankMap) }.toTypedArray()
}
private fun mapScoreToRank(score: Int, rankMap: Map<Int, Int>): String {
return when (val index = rankMap.getValue(score)) {
0 -> "Gold Medal"
1 -> "Silver Medal"
2 -> "Bronze Medal"
else -> (index + 1).toString()
}
}
}
Переваги Kotlin:
Зрозумілі трансформації: Функції
sortedArrayDescending
іwithIndex
роблять процес сортування й індексації простим.Мінімум шуму: Здатність Kotlin виводити типи автоматично скорочує код.
Логічний поділ: Хелпер
mapScoreToRank
додає ясності.
Рішення на Scala: Елегантність функціонального підходу
Scala виводить лаконічність на новий рівень, пропонуючи компактні й виразні рішення:
object Solution {
def findRelativeRanks(score: Array[Int]): Array[String] = {
val rankMap =
score.sorted(Ordering[Int].reverse)
.zipWithIndex
.toMap
score.map(rankMap.andThen(indexToRank))
}
private val indexToRank: Int => String = {
case 0 => "Gold Medal"
case 1 => "Silver Medal"
case 2 => "Bronze Medal"
case i => (i + 1).toString
}
}
Особливості Scala:
Ланцюжки трансформацій: Функції
zipWithIndex
іtoMap
створюють лаконічний і зрозумілий код.Вищі функції: Композиція через
andThen
додає елегантності.
Мене вразив Scala тим, що можна комбінувати Map і функціюrankMap.andThen(indexToRank
). У інших мовах функцію можна композувати лише з іншою функцією.Патерн-матчинг: Дозволяє перетворювати ранги у медалі або числа без зайвих деталей.
Scala ідеально підходить для тих, хто захоплюється функціональним підходом до програмування.
Порівняння продуктивності
Усі три рішення мають схожі етапи: сортування, мапування й форматування результатів. Основна складність визначається операцією сортування (O(n log n)
), що забезпечує ефективність у всіх випадках. Вибір мови зводиться до особистих уподобань та досвіду команди.