Given a positive integer (0 and above, no maximum), convert it into a grade following these rules:

A = 100+
B = 90 - 99
C = 80 - 89
D = 70 - 79
E = 60 - 69
F = 59 and less.


This felt a little boring, so make the grade a + if it's 7,8 or 9 and a - if it's 0,1 or 2. Ignore this for the F and A cases.

An example:

Input:

65


Output:

E


Test cases:

0  -> F
20 -> F
65 -> E
72 -> D-
75 -> D
80 -> C-
99 -> B+
102 -> A
864 -> A


No trailing spaces. One newline after output is fine, but keep it consistent. Functions and full programs are both fine.

This is code golf, so shortest code wins. This was inspired by an Ask Ubuntu question, How to write a shell script to assign letter grades to numeric ranges?. The answers are in bash and python, so slightly spoilers.

Here is a Stack Snippet to generate both a regular leaderboard and an overview of winners by language.

# Language Name, N bytes


where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

# Ruby, <s>104</s> <s>101</s> 96 bytes


var QUESTION_ID=49876;function answersUrl(e){return"http://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),e.has_more?getAnswers():process()}})}function shouldHaveHeading(e){var a=!1,r=e.body_markdown.split("\n");try{a|=/^#/.test(e.body_markdown),a|=["-","="].indexOf(r[1][0])>-1,a&=LANGUAGE_REG.test(e.body_markdown)}catch(n){}return a}function shouldHaveScore(e){var a=!1;try{a|=SIZE_REG.test(e.body_markdown.split("\n")[0])}catch(r){}return a}function getAuthorName(e){return e.owner.display_name}function process(){answers=answers.filter(shouldHaveScore).filter(shouldHaveHeading),answers.sort(function(e,a){var r=+(e.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0],n=+(a.body_markdown.split("\n")[0].match(SIZE_REG)||[1/0])[0];return r-n});var e={},a=1,r=null,n=1;answers.forEach(function(s){var t=s.body_markdown.split("\n")[0],o=jQuery("#answer-template").html(),l=(t.match(NUMBER_REG)[0],(t.match(SIZE_REG)||[0])[0]),c=t.match(LANGUAGE_REG)[1],i=getAuthorName(s);l!=r&&(n=a),r=l,++a,o=o.replace("{{PLACE}}",n+".").replace("{{NAME}}",i).replace("{{LANGUAGE}}",c).replace("{{SIZE}}",l).replace("{{LINK}}",s.share_link),o=jQuery(o),jQuery("#answers").append(o),e[c]=e[c]||{lang:c,user:i,size:l,link:s.share_link}});var s=[];for(var t in e)e.hasOwnProperty(t)&&s.push(e[t]);s.sort(function(e,a){return e.lang>a.lang?1:e.lang<a.lang?-1:0});for(var o=0;o<s.length;++o){var l=jQuery("#language-template").html(),t=s[o];l=l.replace("{{LANGUAGE}}",t.lang).replace("{{NAME}}",t.user).replace("{{SIZE}}",t.size).replace("{{LINK}}",t.link),l=jQuery(l),jQuery("#languages").append(l)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",answers=[],page=1;getAnswers();var SIZE_REG=/\d+(?=[^\d&]*(?:&lt;(?:s&gt;[^&]*&lt;\/s&gt;|[^&]+&gt;)[^\d&]*)*)/,NUMBER_REG=/\d+/,LANGUAGE_REG=/^#*\s*([^,]+)/; body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px} <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"><div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table></div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table></div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table><table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody></table> • Wouldn't there be an A+ and A-? I don't see why we're ignoring them. – ASCIIThenANSI May 9 '15 at 15:55 • @ASCIIThenANSI makes it more interesting to have exceptions, and there is no maximum for the A, so no + – Tim May 9 '15 at 15:55 • That classification board has a bug: the fish version is older and my answer is before it. – Ismael Miguel May 9 '15 at 23:03 • @IsmaelMiguel It was written when earliest post was not the default tie breaker yet (so it doesn't order ties at all). I'll try to fix it at some point though (probably not for this challenge, but at least the source on meta). – Martin Ender May 10 '15 at 0:04 • @MartinBüttner I was just pointing it out. – Ismael Miguel May 10 '15 at 0:06 ## 26 Answers # Python 2, 7270 62 bytes lambda n:"FA"[n>59:1+n/100]or chr(75-n/10)+"+-"[(n+3)%10/3::2]  This is an anonymous function that takes an int and returns the grade as a string. (thanks to @MartinBüttner, @grc and @TheNumberOne for tips) • "EDCB"[n/10-6] -> chr(75-n/10) – grc May 9 '15 at 15:46 • What a clever way to select a character that might be empty! – xnor May 9 '15 at 18:23 # CJam, 34 33 32 bytes riAmd)4/"- +"=S-\Ae<5e>_~'L+o5%<  Okay, I've tried multiple approaches now and am unable to get this below 33, so here goes the explanation: ri e# Read the input and convert to integer Amd e# Take divmod of the input with 10. This leaves the e# number/10 and number%10 on stack )4/ e# Increment the mod by 1 and integer divide by 4. "- +"=S- e# This converts 0,1,2 to 0 and 7,8,9 to 2. Pick - or + e# respectively and remove space in case of 3,4,5 and 6 \Ae<5e> e# To the divisor by 10 scope it to range of [5,10] _~ e# Take a copy and do number * -1 - 1 'L+ e# Add it to char L. This gets us the required grade o e# Output the grade. This removes it from stack 5% e# We now have scoped divisor on stack. Do mod with 5 < e# Both 5 and 10 will return 0, in which case, we don't e# want the + or -. So we do a substr(0, 0). e# 5 represents F and 10, A. For others, it will do e# substr(0,X) where X > 0. Since the string is only e# 1 char long, it doesn't affect at all.  UPDATE: 1 byte saved thanks to a pointer by Dennis Try it online here • What does the s do? – Dennis May 11 '15 at 5:46 • @Dennis converts char +/-/space to string for the last < – Optimizer May 11 '15 at 6:14 • That shouldn't be necessary. Character String - pushes a string. – Dennis May 11 '15 at 13:07 • @Dennis Ah, you are right. I think for some previous version, the usage was different. – Optimizer May 11 '15 at 13:14 # Retina, 43 + 15 = 58 bytes ...+ A .[012]&-
.[789]
$&+ ^9. B ^8. C ^7. D 6. E \d.* F  Retina is a regex language created by Martin Büttner, where the odd-numbered files are the regex to match with, and the even-numbered files are what to replace it with. Each line is a separate file, so I've added 15 bytes for each additional file. ## Explanation It starts by making anything with 3 or more digits an A. It adds a - if it is two-digit number ending with 0, 1, or 2, and + if it ends with 7, 8, or 9. The numbers are then mapped to their grade (e.g. a number starting with 9 is given a B). Any number left over is automatically an F. Unfortunately, ; must be prepended to all but to the last regex to suppress intermediate output. Update: version 0.5.0 has intermediate output off by default, allowing me to save a few bytes. • Are you sure it doesn't output + and - for the F case? – Tim May 11 '15 at 14:47 • @Tim It shouldn't, because \d.* matches and replaces the whole string, + included. – NinjaBearMonkey May 11 '15 at 18:02 • Ahh okay - I can see that now! :) – Tim May 11 '15 at 20:19 ## C, 99 bytes I'm new here, I hope I'm following the rules. char b[3];char*f(n){b[1]=0;n<60?*b=70:n>99?*b=65:(*b=75-n/10,b[1]=n%10<3?45:n%10>6?43:0);return b;}  This function takes the mark as a parameter and returns the grade as a NULL-terminated string. ## Explanation Added whitespace: char b[3]; char *f(n) { b[1] = 0; n<60 ? *b = 70 : n>99 ? *b = 65 : ( *b = 75 - n / 10, b[1] = n % 10 < 3 ? 45 : n % 10 > 6 ? 43 : 0 ); return b; }  Global variables are automatically initialized to zero, so b is filled with NULLs. Since only the first two characters are ever touched, we only have to worry about putting a NULL in b[1] if the grade has only one character. This NULL is inserted at the very beginning of the function. The n parameter is implicitly int. If the grade is less than 60, then it's set to 'F', if it's bigger than 99 it's set to 'A'. In the other cases, the base grade is given by 'E' - (n - 60) / 10, which simplifies to 75 - n / 10. n % 10 gets the units digit of the mark. If it's less than 3 then a - is appended, if it's bigger than 6 a + is appended, otherwise b[1] is nulled (which it already was). ## Test cases #include <stdio.h> char b[3];char*f(n){b[1]=0;n<60?*b=70:n>99?*b=65:(*b=75-n/10,b[1]=n%10<3?45:n%10>6?43:0);return b;} int main() { printf(" 0 -> %s\n", f(0)); printf(" 20 -> %s\n", f(20)); printf(" 65 -> %s\n", f(65)); printf(" 72 -> %s\n", f(72)); printf(" 75 -> %s\n", f(75)); printf(" 80 -> %s\n", f(80)); printf(" 99 -> %s\n", f(99)); printf("102 -> %s\n", f(102)); printf("864 -> %s\n", f(864)); return 0; } Output: 0 -> F 20 -> F 65 -> E 72 -> D- 75 -> D 80 -> C- 99 -> B+ 102 -> A 864 -> A  • Perfect :) Nothing wrong there. – Tim May 10 '15 at 15:26 • difference between ur code and mine is one word "printf" that should save more than 3 byts in case ignored :) – Abr001am May 11 '15 at 20:30 # Pyth, 33 bytes +C-75K@S[/QTT5)1<-@"- +"/heQ4d%K5  Try it online: Demonstration or Test Suite ### Explanation:  implicit: Q = input [/QTT5) create the list [Q/10, 10, 5] S sort @ 1 take the element in the middle K store in K (this results in a number between 5 and 10) -75K 75 - K C char with ASCII-value ... @"- +"/heQ4 "- +"[(Q%10 + 1) / 4] - d remove spaces < %K5 slice [:K%5] + add these two chars and print  # ><> (Fish), 78 71 bytes iii0)?/:0({:'6'(@@+?/'{'01. ;$-o:'4'(?\'7'(?;'+'o
;o'A'\   \'-'o;o'F'\


Method:

• We read the codepoints of first 3 characters x,y,z from the input. If a character is not present the value of its variable's will be -1 implicitly. (ord(c) will mark the codepoint of the character c)
• If z > 0 (3 digit input) print A and exit.
• If x < ord('6') or y < 0 (input < 60) print F and exit.
• Print the character with codepoint 123 - x.
• If y < ord('4') print- and exit.
• If y > ord('6') print+ and exit.
• Exit.

# C, 67 65

Surprisingly, this is quite close to the python solution.

f(i){printf(i<60?"F":i>99?"A":"%c%s",75-i/10,"-\0+"+(i%10+1)/4);}


But in order for this program, to come to such great shortness, sacrifices had to be made:

• If an F or an A is printed printf doesn't even look at the other arguments passed. This is a quite nasty hack.

• If (i%10+1)/4 evaluates to 1 (no + or - should be appended to the grade), the %s formatter receives a pointer to a \0 byte, so nothing is printed. Also quite funny, because I didn't know that you could take the address of an indexed string literal. (e.g. &"string"[i]) (edit: "string"+i is even shorter! Thanks @nutki)

Here the output of the program for the numbers 57 to 102. I made it a hexdump, so we can be sure no weird \0 bytes have been printed.

% seq 44 115 | xargs -n1 ./grade | xxd
0000000: 4646 4646 4646 4646 4646 4646 4646 4646  FFFFFFFFFFFFFFFF
0000010: 452d 452d 452d 4545 4545 452b 452b 452b  E-E-E-EEEEE+E+E+
0000020: 442d 442d 442d 4444 4444 442b 442b 442b  D-D-D-DDDDD+D+D+
0000030: 432d 432d 432d 4343 4343 432b 432b 432b  C-C-C-CCCCC+C+C+
0000040: 422d 422d 422d 4242 4242 422b 422b 422b  B-B-B-BBBBB+B+B+
0000050: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA


The main method used:

main(c,v)char**v;{f(atoi(v[1]));}

• &"string"[i] is unnecessary as it is equivalent to shorter "string"+i with which you can save 2 bytes. – nutki May 13 '15 at 8:55
• i must be objective and upovote this :) congrats , u beated all C records – Abr001am May 13 '15 at 12:45

# CJam, 413937 34 bytes

This is way too long, but I don't think I'll be golfing it further for now.

qiAmd'K@Ae<5e>:X-X5%g@)4/"- +"=*S-


Three bytes saved by Optimizer.

## Explanation

(Slightly outdated)

qi                                    e# Read input and convert to integer.
'K1$e# Push the character K, then copy the input. A/ e# Divide by 10. Ae<5e> e# Clamp the result to the range 5..10."; - e# Subtract from K to get the grade. _'Am e# Duplicate get difference to A. 5%g e# Check that its neither 0 (A) nor 5 (F). @ e# Pull up the other copy of the input. A%)4/ e# ((i % 10) + 1) / 4 "- +"= e# Use that to select -, space, or +. * e# Multiply it with the earlier boolean so that e# it vanishes for A and F. S- e# Remove the space if there is one.  # GNU sed, 73 + 1 = 74 bytes The + 1 is for the -r parameter. s/^[1-5]?.$/F/
s/.{3,}/A/
s/[7-9]$/+/ s/[3-6]$//
s/[0-2]$/-/ y/9876/BCDE/  # Python 2, 948884 69 bytes lambda g:g>99and'A'or[chr(75-g/10)+'-+'[g%10>2:1-(g%10>6)],'F'][g<60]  # JavaScript (ES6), 66 bytes Straight. F=n=>n<60?'F':n>99?'A':'EDCB'[n/10-6|0]+(n%10>6?'+':n%10<3?'-':'') // TEST (in Firefox) for(i=0;i<111;i++)document.write(i+'='+F(i)+' ') # R, 107105 99 bytes Not a very good effort I'm afraid, but I will try and golf it more later. cat(LETTERS[11-(r=min(max(scan(),59),100))%/%10],if(r>59&r<100)c('-','','+')[(r%%10+1)/4+1],sep='')  Edit Dropped a couple of ifs. Fixed the case and an incorrect result for 100. Now to get rid of the ifelses. Got rid of ifelses. • I think you want LETTERS rather than letters. – Alex A. May 10 '15 at 1:12 # Perl, 66 62 bytes This can probably be golfed more. Also a different way might be better. $_=$_>99?A:$_<60?F:s/\d$/$&>6?"+":$&<3?"-":""/re;y/9876/BCDE/  +1 for -p Run with: echo 72 | perl -pE'$_=$_>99?A:$_<60?F:s/\d$/$&>6?"+":$&<3?"-":""/re;y/9876/BCDE/'  • Why not use -p and drop the say? – ThisSuitIsBlackNot May 10 '15 at 3:49 • @ThisSuitIsBlackNot thanks! Updated – hmatt1 May 11 '15 at 1:10 # Javascript (ES6), 78 79 bytes This really isn't the smartest option, but I did what I could. F=n=>'FEDCBA'[n[2]?5:n<60?0:n[0]-5]+(n[2]||n<60?'':'-+\n'[n[1]<3?0:n[1]>6?1:2])  Simply pass the grade as a string, and it will return it's grade letter. The string part in very important. You can check a testcase here: console._RELAY_TO_DOC=true; //non-es6 version: function F(n){return 'FEDCBA'[n[2]?5:n<60?0:n[0]-5]+(n[2]||n<60?'':'-+\n'[n[1]<3?0:n[1]>6?1:2])} var testcases=[0,20,65,72,75,77,80,90,99,100,102,180,1000], results={}; for(var i in testcases) { results[testcases[i]]=F(testcases[i]+''); } console.log(results); <script src="http://ismael-miguel.github.io/console-log-to-document/files/console.log.min.js"></script> If the aditional space after the letter isn't allowed, I will happily remove it. It wasn't! This increased my code by 1 byte, but nothing (too) serious. • @Tim Fixed it. I hope it is enough. Quoting yourself: "One newline after output is fine, but keep it consistent.". I think that is consistent enough. – Ismael Miguel May 11 '15 at 14:51 # C#, 143127112 88 bytes string g(int n){return n>=100?"A":n<=59?"F":(char)(75-n/10)+(n%10>6?"+":n%10<3?"-":"");}  I tried to be clever by doing ASCII number mods, but it seems I wasn't alone! Thanks to Tim for advice on lists instead of ifs. Thanks to DarcyThomas for pointing out I could use nested ternary operators. • Can you not cut down on the ifs using lists? – Tim May 11 '15 at 14:44 • I'm not sure what you mean by using lists, could you explain a little? – Transmission May 11 '15 at 15:57 • In python I can do this: [item1,item2][condition]. If the condition is True it gives the 2nd item, if False the first. – Tim May 11 '15 at 16:03 • Good idea! Added that. – Transmission May 11 '15 at 16:29 • I think you could use ternary if statements e.g., return <condition> ? <true result> : <false result> Note you can also nest them so return <condition> ? <true result> : <condition> ? <2nd true result> : < 2nd false result> – DarcyThomas May 11 '15 at 20:18 # Haskell, 78 bytes The first line feels wasteful, costing 14 bytes, but I couldn't find a shorter version without it. (#)=replicate a="A":a f=(!!)$60#"F"++[g:s|g<-"EDCB",s<-3#"-"++4#""++3#"+"]++a


## Explanation

The operator # is a shorthand for creating n copies of its second argument. List a is an infinite list of Strings "A". Function f indexes into a list of all grades for n=0,1,... The list comprehension builds the "middle part" of this list (grades E to B); g is a single Char that is prepended to the String s (which may be empty).

## Usage

ghci> map f [0,20,65,72,75,80,99,102,864]
["F","F","E","D-","D","C-","B+","A","A"]


## C, 102 bytes

int f(int h){int b,c;printf("%c%c",b?65:!c?70:75-h/10,!(b=h>99)*(c=h>59)*(((h%10<3)*45+(h%10>6)*43)));


}

## Usage

#include <stdio.h>
int f(int );
int main(){
int c;
scanf("%d",&c);
f(c);
}

• You are missing the + and - part. – Optimizer May 9 '15 at 22:48
• ah ok .... miss that – Abr001am May 9 '15 at 22:48
• too long :( .... – Abr001am May 10 '15 at 12:27

# dc, 52

[Anq]sa[Fnq]sf[q]sn16o?A~rd9<ad6>f20r-n1+4/d1=n45r-P


### Output

$for i in {0,20,65,72,75,80,99,102,864}; do printf "{%s -> %s} "$i $(dc -e '[Anq]sa[Fnq]sf[q]sn16o?A~rd9<ad6>f20r-n1+4/d1=n45r-P' <<<$i); done
{0 -> F} {20 -> F} {65 -> E} {72 -> D-} {75 -> D} {80 -> C-} {99 -> B+} {102 -> A} {864 -> A} 


# TI-Basic, 7974 76 Bytes

Input N
If N>99
105->N
sub("FFFFFFEDCBA",1+int(N.1),1
If Ans!="F
Ans+sub("---    +++",1+fPart(N.1),1
Ans

• That does not work for numbers less than 10. – lirtosiast May 16 '15 at 20:53
• Nice catch, Tom, it was missing 1+ – Timtech May 19 '15 at 12:22
• This also has (invisible) trailing spaces whenever there is no + or -. – lirtosiast May 19 '15 at 19:51

# TI-BASIC, 6968 66 bytes

.1Ans
sub("F?E-E+D-D+C-C+B-B+A",1+2max(0,min(9,int(2Ans)-11)),int(e^(Ans<10 and Ans≥6 and iPart(2.2-5fPart(Ans


TI-BASIC is not good for string manipulation.

Input on the calculator homescreen, in the form of [number]:[program name].

Formatted:

.1Ans
sub(                      //Syntax for the substring command is sub(string, index, length)

"F?E-E+D-D+C-C+B-B+A"                  //String that encodes possible grades

,1+2max(0,min(9,            ))         //Starts at "F" if input <60, "A" if >=100
int(2Ans)-11           //(Input-55)/5, so starts at "E" from 60 to 64,
//second E from 65-69, D from 70 to 74, &c.

,int(e^(                                   //length 1 if false, 2 (includes +/-) if true
Ans<10 and Ans≥6 and               //grade between 60 and 100
iPart(               //1 if abs. val. of below >= 0.2
2.2-5fPart(Ans  //2.2-.5(last digit)


This can probably be golfed further.

# C#, 82 bytes

Func<int,string>g=s=>s>99?"A":s<60?"F":(char)(75-s/10)+(s%10<3?"-":s%10>6?"+":"");


Here's a fiddle with some test-cases.

# JavaScript (ES6), 86 83 bytes

What's really eating up characters is the String.fromCharCode and the +/- condition... I strongly suspect there's a clever way to shorten at least one of them.

f=n=>n>99?'A':n<60?'F':String.fromCharCode(75.9-n/10|0)+(n%10<3?'-':n%10>6?'+':'');

• If you want short code, String.fromCharCode is almost always useless. Use string indexing (see the other javascript answers) – edc65 May 11 '15 at 13:06
• Anyway, ~~(.1*-n+75.9) --> 75.9-n/10|0 – edc65 May 11 '15 at 13:09
• @edc65 Thanks for the golfing advice! I'll keep string indexing in mind for the next occasion. – vvye May 11 '15 at 15:17

# PHP5.5, 73 bytes

Once again, not the shortest one.

But it works!

<?=($n=$_GET[n])<59?F:($n>99?A:'BCDE'[$n[0]-6].'+-'[$n[1]<3?1:2*$n[1]<5])


I've classified it under PHP5.5 instead of just PHP since this uses syntax that is only valid for PHP5.5 and PHP5.6.

http://php.net/manual/en/migration55.new-features.php

# Perl, 52

#!perl -p
$_=$_>99?A:$_<60?F:"$_"^"s";y/JK7890-6/BC+++\-\--/d


# Ruby, 58 Bytes

Couldn't believe that there are no Ruby ones here. On reflection it's fairly similar to some that are here already but anyway:

->x{x<60?'F':x>99?'A':(75-x/10).chr+'+-'[(x+3)%10/3].to_s}


Try it here

# Excel, 100 bytes

=IF(A1<60,"F",IF(A1>99,"A",MID("EDCB",INT(A1/10)-5,1)&IF(MOD(A1,10)<3,"-",IF(MOD(A1,10)>6,"+",""))))
`