Hi friends! I was going through my Twitter timelin...
# codereview
p
Hi friends! I was going through my Twitter timeline and this post called my attention. Someone posted a Rust version which was quite clean, and I was tempted to try something different with Kotlin. I came up with:
Copy code
fun grade(x: Int): String = listOf("A", "B", "C", "D").getOrElse((99 - x).div(10)) { "F" }
I am pretty sure there are cooler ways of achieving this (even my maths can be simplified), so I was wondering what would you do in this case. 🙂 Cheerio!
j
I would put 60-> D, 70 -> C etc. into a treemap and use the floorEntry method
p
Thanks for sharing! Using
floorEntry
really does the trick!
d
I would probably just use a when statement instead.
Copy code
fun getGrade(score:Int) = when {
  score >= 90 -> "A"
  score >= 80 -> "B"
  score >= 70 -> "C"
  score >= 60 -> "D"
  else -> "F"
}
At least for this use case. tree map etc is overkill for 5 entries, and it kind of hides the intent a little bit. Also, the example you have given could be written more concisely even outside of kotlin:
Copy code
public string CheckGrade(int score) 
{
  if (score >= 90) return "A";
  if (score >= 80) return "B";
  if (score >= 70) return "C";
  if (score >= 60) return "D";
  return "F"
}
No need to use "else" if each branch returns.
👆 1
j
Ahh but then you need to unit test every branch in that when. :)
It's a style thing. I try to avoid branches. Feels like I'm defining the mapping outside of code and the code is more data driven
d
I agree with that sentiment @Jacob, but I think sometimes "data driving" certain use-cases is actually counter-productive. I think "numeric to letter grade" is one of the use-cases that data-driven leads to added complexity, reduced clarity, and even poorer performance. Now, if you needed to support different systems (some classes/schools use 85+ is A, or maybe you sometimes need to have A+, A, A-, B+, etc...), then it would likely make sense to externalize the rules and potentially use a SortedMap as the mechanism for lookup.
💯 2
Anyway, I don't think your suggestion is wrong, I simply was stating what I would probably do when given the implied requirements of that method.
👍 1
Another possible approach in Kotlin:
Copy code
val grades get() = sequenceOf(
   90 to "A",
   80 to "B",
   70 to "C",
   60 to "D",
   Int.MIN_VALUE to "F"
)

fun grade(score: Int) = 
    grades
      .filter { (num, _) -> score > num }
      .map { (_, grade) -> grade }
      .first()
g
to bump a dead thread, I'd make the value a subject of a when clause and use the
in
operator:
Copy code
require(score in 0 .. 100) { "score !in 0..100: $score" } 
val grade = when(score){
  in 0 ..< 60 -> "F"
  in 60 ..< 70 -> "D"
  in 70 ..< 80 -> "C"
  in 80 ..< 90 -> "B"
  in 90 .. 100 -> "A"
  else -> unreachable()
}