dev.to staff

Posted on

# Daily Challenge #68 - Grade Book

Today's challenge is to write a function that accepts three integer values, calculates the mean, then returns the letter value associated with that grade. If the mean of those three integers ends in a number greater than five, append a plus sign to the letter grade. If it is less than five, append a minus sign.

```Numerical Score      Letter Grade
90 <= score <= 100    'A'
80 <= score < 90      'B'
70 <= score < 80      'C'
60 <= score < 70      'D'
0 <= score < 60      'F'
```

Examples:
`grade(64, 55, 92)` => `C-` (70.3)
`grade(99, 89, 93)` => `A-` (93.6)
`grade(33, 99, 95)` => `C+` (75.6)

Happy coding!

This challenge was inspired by CodeWars user danleavitt0. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Alvaro Montoro

CSS

This will only work on Safari because, for some forsaken reason, Safari is the only browser that supports min() and max() at the moment. Which is funny considering that normally it is the other way around 🤷‍♂️

This can be represented as a decision machine with different ranges for different grades. Then the idea would be to have an element to which we pass the three grades as CSS variables (all integers or it will fail), calculate the z-index to set which element should be visible. I would need to double check the logic, I think it's correct. Also, I think the code can be simplified.

Here is the code running. Remember it will only work on Safari:

Cagatay Kaya

Too much ternary operators...

``````const grade = (a,b,c) =>{
const mean = (a + b + c) / 3;

const prefix = mean % 10 < 5 ? '-':
mean % 10 > 5 ? '+': '';

return   mean < 59 ?          `F (\${mean})`:
mean < 70 ? `D\${prefix} (\${mean})` :
mean < 80 ? `C\${prefix} (\${mean})`:
mean < 90 ? `B\${prefix} (\${mean})` :
`A\${prefix} (\${mean})`;

}
``````

Amin • Edited

You could use something like that:

``````({"-1": "-", "1": "+", "0": ""})[mean.toString().localeCompare("5")]
``````

Not tested but I believe it would work in JavaScript.

Zohar Peled

I've Started to write a c# answer only to find out I'm going the exact same route as your answer...

Kerri Shotts

Here's mine:

``````const sum = (...nums) => nums.reduce((total, cur) => total + cur, 0);
const lastDigit = grade % 10;
const gradeLetter = Object.entries({90: "A", 80: "B", 70: "C", 60: "D", 0: "F"})
.sort(([a], [b]) => a < b)
[1] + ((lastDigit < 5) ? "-" :
(lastDigit > 5) ? "+" : "");
};
``````

Casi Imin

Nice Js!

Oleksii Filonenko

Rust:

``````fn grade(a: u32, b: u32, c: u32) -> String {
let mean = (a + b + c) / 3;
let letter = match dbg!(mean) {
_ if (90..=100).contains(&mean) => "A",
_ if (80..90).contains(&mean) => "B",
_ if (70..80).contains(&mean) => "C",
_ if (60..70).contains(&mean) => "D",
_ if (0..60).contains(&mean) => "F",
_ => unreachable!("mean ({}) can't be < 0", mean),
};
let sign = if mean % 10 < 5 { "-" } else { "+" };
format!("{}{}", letter, sign)
}
``````

Casi Imin • Edited

Python

``````#The function
def call_mean (x,y,z):
mean = ((x+y+z)/3)
mean_s = (str(mean))
print ("\nMean: ",mean)
if (mean > 100): print("\nWrong input, try again...")
else:
#The statement
if ((mean <= 100 and mean >= 90)):
if (mean_s[1] >= '5'): print ("A+")
else: print ("A-")
elif ((mean < 90 and mean >= 80)):
if (mean_s[1] >= '5'): print ("B+")
else: print ("B-")
elif ((mean < 80 and mean >= 70)):
if (mean_s[1] >= '5'): print ("C+")
else: print ("C-")
elif ((mean < 70 and mean >= 60)):
if (mean_s[1] >= '5'): print ("D+")
else: print ("D-")
elif ((mean < 60 and mean >= 0)):
if (mean_s[1] >= '5'): print ("F+")
else: print ("F-")

#Three value from input
x = int(input("first int: "))
y = int(input("second int: "))
z = int(input("third int: "))

#Call the function
call_mean(x,y,z)
``````

Oleksii Filonenko

``````(def grades {"A" [90 101]
"B" [80 90]
"C" [70 80]
"D" [60 70]
"F" [0 60]})

"Calculates a letter for the mean of given grades."
[a b c]
(let [mean (quot (+ a b c) 3)
sign (if (< (rem mean 10) 5) "-" "+")
(filter (fn [[_ [low high]]]
(and (>= mean low) (< mean high))))
(map key)
first)]
(str letter sign)))
``````

Amin • Edited

Elm

``````module GradeBook exposing (gradeBook)

case compare (modBy 10 mean) 5 of
EQ ->
""

LT ->
"-"

GT ->
"+"

gradeBook : Int -> Int -> Int -> String
let
mean =

in
if mean < 60 then

else if mean < 70 then

else if mean < 80 then

else if mean < 90 then

else
``````

Tests

``````module GradeBookTest exposing (suite)

import Expect
import Test exposing (Test)

suite : Test
suite =
[ Test.test "It should return C- when passing 64, 55 & 92" <|
\_ ->
Expect.equal "C-" <| gradeBook 64 55 92
, Test.test "It should return A- when passing 99, 89 & 93" <|
\_ ->
Expect.equal "A-" <| gradeBook 99 89 93
, Test.test "It should return C+ when passing 33, 99 & 95" <|
\_ ->
Expect.equal "C+" <| gradeBook 33 99 95
, Test.test "It should return C when passing 64, 70 & 92" <|
\_ ->
Expect.equal "C" <| gradeBook 64 70 92
]
``````

Rebecca Skinner

Here's my type-level implementation in haskell:

``````{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DataKinds #-}

module Lib where
import GHC.TypeLits

data PlusMinus g = Plus g | Minus g | None g

data Grade = A | B | C | D | F

infixr 5 :->

type StandardGradingCurve = '[90 :-> A, 80 :-> B, 70 :-> C, 60 :-> D, 0 :-> F]

LookupGrade' '[] k k' = F
LookupGrade' ((k :-> v) ': c) k k' = v
LookupGrade' ((k :-> v) ': c) 0 k' = LookupGrade' c k' k'
LookupGrade' ((k :-> v) ': c) n k' = LookupGrade' ((k :-> v) ': c) (n - 1) k'

type family IfThenElse (cond :: Bool) (whenTrue :: b) (whenFalse :: b) :: b where
IfThenElse True trueBranch falseBranch = trueBranch
IfThenElse False trueBranch falseBranch = falseBranch

type family LessThan (a :: Nat) (b :: Nat) :: Bool where
LessThan a a = False
LessThan a 0 = False
LessThan 0 b = True
LessThan a b = LessThan (a - 1) (b - 1)

type family OnesFamily (n :: Nat) :: Nat where
OnesFamily 0 = 0
OnesFamily n = IfThenElse (LessThan n 10) n (OnesFamily (n - 10))

type family MakePlusMinus (n :: Nat) (val :: a) :: PlusMinus a where
MakePlusMinus score val =
IfThenElse (LessThan (OnesFamily score) 5) (Minus val) (IfThenElse (LessThan 5 (OnesFamily score)) (Plus val) (None val))

type family Sum (vals :: [Nat]) :: Nat where
Sum vals = Sum' 0 vals

type family Sum' (total :: Nat) (vals :: [Nat]) :: Nat where
Sum' n '[] = n
Sum' n (a ': as) = Sum' (n + a) as

type family Length (vals :: [a]) :: Nat where
Length '[] = 0
Length (val ': vals) = 1 + (Length vals)

type family Mean (vals :: [Nat]) :: Nat where
Mean vals = Div (Sum vals) (Length vals)

``````

Eddie Hale • Edited

My first stab at writing something other than "Hello World!" in golang:

``````package main

import (
"fmt"
"math"
)

func grade(x, y, z float64) string {
mean := float64((x + y + z) / 3)

if mean >= 90 && mean <= 100 {
} else if mean >= 80 && mean < 90 {
} else if mean >= 70 && mean < 80 {
} else if mean >= 60 && mean < 70 {
} else if mean >= 0 && mean < 60 {
}

if math.Mod(mean, 10.0) < 5 && grade != "F" {
} else if math.Mod(mean, 10.0) >= 5 && grade != "F" {
}

}

func main() {

fmt.Println(output)
}
``````

dillan teagle • Edited

This is my quick python solution

``````def grade(x, y, z):
board = { 9: "A", 8: "B", 7: "C", 6: "D", 5: "F" }
sum = x + y + z
mean = sum / 3
if mean >= 5:
return board.get(mean)

``````

Michael Baas • Edited

APL (I'm using Dyalog APL):

`{md←10|m←(+⌿÷⍴)⍵ ⋄ ((1+60 70 80 90 101⍸m)⊃'FDCBA'),' -+'[1+(md≠5)×1+(,5)⍸md]}`

If you think that's too short to work - here's the proof:
First, let's define that as a function:
`getMark←{md←10|m←(+⌿÷⍴)⍵ ⋄ ((1+60 70 80 90 101⍸m)⊃'FDCBA'),' -+'[1+(md≠5)×1+(,5)⍸md]}`

And now you can simply do
`getMark 64 55 92`
C-
`getMark 99 89 93`
A-
`getMark 33 99 95`
C+

And if you still don't believe me, try it here or there! ;-)
(These online solutions use the symbol ≢ instead of ⍴ - they are equivalent in this case, but ≢ renders incorrectly on dev.to. There's also an issue with another APL-Character: ⍸ - if someone from the dev-team would contact me, I'd love to help sorting that out...)

K.V.Harish • Edited

My solution in js

``````const grade = (...values) => {
const grades = {9: 'A', 8: 'B', 7: 'C', 6: 'D'},
mean = values.reduce((acc, value) => acc += value, 0) / values.length;
return grades[Math.floor(mean / 10)] ? `\${grades[Math.floor(mean / 10)]}\${mean >= (Math.floor(mean / 10) * 10 + 5) ? '+' : '-'}` : Math.floor(mean / 10) > 9 ? 'A+' : 'F'
}
``````

E. Choroba

Perl solution, using a regex to extract the last digit (but we need to replace 100 by 99 for it to work).

``````#!/usr/bin/perl
use warnings;
use strict;
use List::Util qw{ sum };

my \$mean = int(sum(@_) / @_);
return 'F' if \$mean < 60;

\$mean = 99 if \$mean == 100;
my \$sign = (\$mean =~ /(.)\$/)[0] < 5 ? '-' : '+';

return qw( D C B A )[ (\$mean - 60) / 10 ] . \$sign
}

use Test::More tests => 6;

is grade(100, 100, 100) => 'A+';
is grade( 60,  60,  60) => 'D-';
is grade( 64,  55,  92) => 'C-';
is grade( 99,  89,  93) => 'A-';
is grade( 33,  99,  95) => 'C+';
is grade( 60,  60,  59) => 'F';
``````

Melvin Yeo

I wrote this in Python with the assumption that the input of the function will all be integers between 0 and 100.

``````def grade(*grades):
grade_range = [(90, 'A'),(80, 'B'),(70, 'C'),(60, 'D')]
mean = 0

mean += score

polarity = "+" if mean % 10 >= 5 else "-"

return "F" + polarity
``````

Avalander

### Scala

``````def grade (a: Int, b: Int, c: Int): String = {
val average = (a + b + c) / 3f
letter(average) ++ sign(average)
}

def letter (grade: Float): String =
case x if x >= 90 => "A"
case x if x >= 80 => "B"
case x if x >= 70 => "C"
case x if x >= 60 => "D"
case _            => "F"
}

def sign (grade: Float): String =
case x if x < 5 => "-"
case x if x > 5 => "+"
case _          => ""
}
``````