DEV Community

dev.to staff
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!

Latest comments (19)

Collapse
 
kvharish profile image
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'
}
Collapse
 
karthicktamil17 profile image
karthick rajan

Solved Using Purescript inspired from Amin Nairi

grade :: Int -> String
grade average =
    case compare (mod 10 average) 5 of
        EQ ->
          ""

        LT ->
          "-"

        GT ->
          "+"  

resultGrade :: Int -> Int -> Int -> String
resultGrade grade1 grade2 grade3 =
   let 
        average = (grade1 + grade2 + grade3) / 3

        finalGrade = grade $ fromMaybe 0 $ fromNumber $ Math.round 
                      (toNumber average)
   in
   if average < 60 then 
       "F" <> finalGrade

   else if average < 70 then 
       "D" <> finalGrade 

   else if average < 80 then 
       "C" <> finalGrade 

   else if average < 90 then 
       "B" <> finalGrade 

   else 
       "A" <> finalGrade
Collapse
 
avalander profile image
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 =
  grade match {
    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 =
  (grade % 10) match {
    case x if x < 5 => "-"
    case x if x > 5 => "+"
    case _          => ""
  }
Collapse
 
mbaas2 profile image
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...)

Collapse
 
teaglebuilt profile image
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)

Collapse
 
eddiehale3 profile image
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)
    grade := ""

    if mean >= 90 && mean <= 100 {
        grade = "A"
    } else if mean >= 80 && mean < 90 {
        grade = "B"
    } else if mean >= 70 && mean < 80 {
        grade = "C"
    } else if mean >= 60 && mean < 70 {
        grade = "D"
    } else if mean >= 0 && mean < 60 {
        grade = "F"
    }

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

    return grade
}

func main() {
    //output := grade(64, 55, 92)
    //output := grade(99, 89, 93)
    output := grade(33, 99, 95)

    fmt.Println(output)
}
Collapse
 
colorfusion profile image
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

    for _, score in enumerate(grades):
        mean += score

    mean = int(mean / len(grades))

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

    for grade in grade_range:
        if mean >= grade[0]:
            return grade[1] + polarity

    return "F" + polarity
Collapse
 
choroba profile image
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 };

sub grade {
    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';
Collapse
 
rebeccaskinner profile image
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 :->
data GradeMapping minScore grade = minScore :-> grade

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

type family LookupGrade (c :: [GradeMapping score grade]) (s :: score) :: grade where
  LookupGrade m k = LookupGrade' m k k

type family LookupGrade' (c :: [GradeMapping score grade]) (s :: score) (s' :: score) :: grade where
  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'
  LookupGrade' ((kvm) ': c) k k' = LookupGrade' c k 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)

type family CalcGrade (vals :: [Nat]) :: PlusMinus Grade where
  CalcGrade vals = MakePlusMinus (Mean vals) (LookupGrade StandardGradingCurve (Mean vals))
Collapse
 
brightone profile image
Oleksii Filonenko

Clojure (my new adventure):

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

(defn grade
  "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) "-" "+")
        letter (->> grades
                   (filter (fn [[_ [low high]]]
                             (and (>= mean low) (< mean high))))
                   (map key)
                   first)]
    (str letter sign)))