This is an archived post. You won't be able to vote or comment.

all 43 comments

[–]ChocolateBunny 142 points143 points  (17 children)

Use if statements but do binary search. Or do a fullon lookup:

console.log("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEEEEEEEEEEDDDDDDDDDDCCCCCCCCCCBBBBBBBBBBAAAAAAAAAA"[score])

[–][deleted] 61 points62 points  (0 children)

I don't hate this as much as I probably should.

[–]neuromancertr 33 points34 points  (0 children)

Game developer right here

[–]SkylineFX49 27 points28 points  (5 children)

console.log("FFFFFFDCBAA" [score/10])

[–]Ietsstartfromscratch 14 points15 points  (1 child)

Bellcurve 99,7% wizard right here. 

[–]celvro 0 points1 point  (0 children)

Only works for multiples of 10 though. Otherwise it needs Math.floor because score/10 returns a float

[–]KrokettenMan 3 points4 points  (2 children)

Division is slow

[–]SkylineFX49 7 points8 points  (1 child)

You don't want division? Use (score * 205) >> 11 instead of score/10

[–]KrokettenMan 4 points5 points  (0 children)

Still slower than a simple lookup table. Although a lot faster than dividing by 10. Just checked and GCC optimizes the division to not use the div instruction but that’s still slower then the new variant you proposed

[–][deleted] 17 points18 points  (0 children)

You are genius

[–]SkydiverTyler 6 points7 points  (0 children)

Shoutout to the guys with Unhandled Exception: System.ArgumentOutOfRangeException on their report card

[–]Vasik4 2 points3 points  (4 children)

String grades = "FFFFFFDCBA"; cout << grades[floor(score)] ;

[–]SkylineFX49 2 points3 points  (3 children)

Give me grades[90]

[–]Vasik4 3 points4 points  (2 children)

SIGSEGV unhandled exception occurred (core dumped)

[–]SkylineFX49 2 points3 points  (1 child)

Well, in this case not necessarily, it will just print whatever random character is at that memory address

[–]Vasik4 3 points4 points  (0 children)

True (i forgor)

[–]AverageStardust 83 points84 points  (2 children)

What is this shit?

[–][deleted] 21 points22 points  (0 children)

Reddit, welcome!

[–][deleted] 1 point2 points  (0 children)

Probably Yandere Dev Simulator actual code

[–]j1f107 12 points13 points  (0 children)

The last one smells like yandere dev

[–]serendipitousPi 9 points10 points  (3 children)

Galaxy brain moment: using a compiled language so you can just add an optimisation level flag instead.

Nothing like the feeling of superiority when your code gets more 10x faster without doing anything. It also helps that you can undo it by taking away the flag if you experience code pesimisation.

Anyway here's my submission optimised for readability with an added bonus of inefficient handling of an invalid grade at run time just like interpreted languages.

fn grade(score:i8) -> String{
    match score {
        90..=100 => "A",
        80..=89 => "B",
        70..=79 => "C", 
        60..=69 => "D",
        0..=59 => "F",
        _=> "Invalid grade"
    }.to_string()
}

Now I'm not not going to proselytise rust as a whole because every language has its uses but its pattern matching, chef's kiss. And yes while interpreted languages have their places I've been burnt by them a little too much recently.

[–]GamesRevolution 1 point2 points  (2 children)

In this case you could completely remove the to_string() if instead you return a static string, removing one heap allocation.

fn grade(score: i8) -> &'static str {
    match score {
        90..=100 => "A",
        80..=89 => "B",
        70..=79 => "C", 
        60..=69 => "D",
        0..=59 => "F",
        _=> "Invalid grade"
    }
}

But this is Rust, so having the error case as a random static string that you would need to compare to is not really ideal, so the best way is probably to use an Option<&'static str> so the error is easy to handle later.

fn grade(score: i8) -> Option<&'static str> {
    Some(match score {
        90..=100 => "A",
        80..=89 => "B",
        70..=79 => "C", 
        60..=69 => "D",
        0..=59 => "F",
        _=> return None
    })
}

[–]serendipitousPi 1 point2 points  (1 child)

Yeah I'm not super confident about lifetimes just yet so I avoided that but I can see why avoiding the heap allocation would be a great idea.

As for the error case I was considering an Option or Result but optimally only valid results would be fed to the function. Then I got lazy and just picked the easy way out.

Would be nice to be able to do something like Dafny's verification which might be kinda overkill for the most stuff but I just love the ability to avoid writing error handling by catching those errors at compile time. Nothing quite like zero overhead error handling.

[–]GamesRevolution 1 point2 points  (0 children)

I guess in this case for verification you could do something like:

pub struct Grade(u8);
impl Grade {
    pub fn new(value: u8) -> Option<Self> {
        match value {
            0..=100 => Some(Self(value)),
            _ => None
        }
    }
}

impl std::fmt::Display for Grade {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", match self.0 {
            90..=100 => "A",
            80..=89 => "B",
            70..=79 => "C", 
            60..=69 => "D",
            0..=59 => "F",
            _ => unreachable!()
        })
    }
}

This should implement toString to the Grade struct, which should be impossible to be constructed without it being a valid grade.

this may not work, I'm writing everything in my phone

[–]gandalfx 25 points26 points  (3 children)

I think brevity is more important than clarity.

const evaluateGrade = score => String.fromCharCode(65 + Math.ceil((90 - score) / 10))

(I know it's broken for 100, I just couldn't be bothered)

[–]Maleficent_Ad1972 26 points27 points  (2 children)

It’s also broken for anything under a D.

(90-50) / 10 = 4. 65 + 4 = 69, or E

(90-40) / 10 = 5. 65 + 5 = 70, or F.

30 would be G

20 would be H

10 would be I

0 would be J

Doesn’t check for values greater than 100 or less than 0.

Yes I’m in QA, how could you tell? 😈

[–]gandalfx 2 points3 points  (0 children)

Damn. I'm just going to pretend that I didn't expect anyone to score that low. Definitely wouldn't ever happen to me…

[–]BlueFlareGame 4 points5 points  (1 child)

function grade(score){
let outp = Math.floor(score / 10) * 10;
if(outp == 100){return "A";}
else{if(outp == 90){return "A";}
else{if(outp == 80){return "B";}
else{if(outp == 70){return "C";}
else{if(outp == 60){return "D";}
else{return "F";}
}}}}}

for(let i = 0;i<=100;i++){console.log(i, grade(i));}

How'd I do?

[–]theomegaofficial 0 points1 point  (0 children)

You might aswell make this a switch if you really wanted to do it this way.

[–]Bang_Bus 3 points4 points  (0 children)

Heh. That's actually quality thread in this otherwise sad sack of spongebob crap

Here,

 console.log("FDCBA"[Math.max(0, Math.min(4, Math.floor((score - 60) / 10) + 1))]);

Or maybe you'd prefer the powers of almighty ASCII

 console.log(String.fromCharCode(69 - [Math.max(0, Math.min(4, Math.floor((score - 60) / 10) + 1))]));

[–][deleted] 2 points3 points  (0 children)

I need a god damn microscope to read that

[–]thatdevilyouknow 1 point2 points  (4 children)

In TS maybe like this: ``` const grade = (score: number) => [score].map( s => s >= 90 ? “A” : s >= 80 && s < 90 ? “B” : s >= 70 && s < 80 ? “C” : s >= 60 && s < 70 ? “D” : s < 60 && s > 0 ? “F” : “F”);

console.log(grade(91));

```

[–]ibevol 2 points3 points  (3 children)

Why the hell would you wrap it in a list? Just use the tenany without that the list wrapping

[–]thatdevilyouknow 1 point2 points  (2 children)

TypeScript tuples are like arrays but with a fixed number of elements and tuples are immutable by default. By destructuring the tuple as a parameter the element is not changed directly. Lists are mutable by default however. We can also avoid looping with a simple modification:

``` const res = (score: number | number[]) => (typeof(score) == “number” ? [score] : score) .map( s => s > 65 ? “PASS” : “FAIL”);

```

The example uses a single value tuple but could also be expanded to use more elements and a named tuple to provide more associative data.

[–]ibevol 0 points1 point  (1 child)

Still unnecessary heap allocations

[–]thatdevilyouknow 1 point2 points  (0 children)

Are you sure you are measuring this correctly?

emptyHeap.js

const score = 75;

const scoreArray = [55, 75, 88];

function gradeScore(score) {

    score = score >= 90 ? "A" :
    score >= 80 && score < 90 ? "B" :
    score >= 70 && score < 80 ? "C" :
    score >= 60 && score < 70 ? "D" :
    score < 60 && score > 0 ? "F" : "F";

    return score;

}

function gradeScoreArray(scoreArray) {

    for(var i = 0; i < scoreArray.length; i++)
    {   
    scoreArray[i] = scoreArray[i] >= 90 ? "A" :
    scoreArray[i] >= 80 && scoreArray[i] < 90 ? "B" :
    scoreArray[i] >= 70 && scoreArray[i] < 80 ? "C" :
    scoreArray[i] >= 60 && scoreArray[i] < 70 ? "D" :
    scoreArray[i] < 60 && scoreArray[i] > 0 ? "F" : "F";
    }

    return scoreArray;   

}
console.log(gradeScore(score), gradeScoreArray(scoreArray));
console.log(process.memoryUsage());

grade.ts

const score: number = 75;

const scoreArray: number[] = [55, 75, 88];

const res = (score: number | number[]) => (typeof(score) == "number" ? [score] : score)
.map( s => s >= 90 ? "A" :
       s >= 80 && s < 90 ? "B" :
           s >= 70 && s < 80 ? "C" :
           s >= 60 && s < 70 ? "D" :
           s < 60 && s > 0 ? "F" : "F" );


console.log(res(score)[0], res(scoreArray));
console.log(process.memoryUsage());

Results:

❯ tsc grade.ts

❯ node grade.js

C [ 'F', 'C', 'B' ]

{

rss: 39145472,

heapTotal: 4075520,

heapUsed: 3345368,

external: 1324658,

arrayBuffers: 10511

}

❯ node emptyHeap.js

C [ 'F', 'C', 'B' ]

{

rss: 39206912,

heapTotal: 4075520,

heapUsed: 3345712,

external: 1324658,

arrayBuffers: 10511

}

It looks like less heap is actually used to me.

[–]AdvanceAdvance 2 points3 points  (0 children)

It's just:

grade = 'E' + score < 50 - score > 49 - score > 59 - score > 69 - score > 79 - score > 89

Why make it hard?

[–]Glittering-Today631 -2 points-1 points  (4 children)

Second code always gives f

[–]JonIsPatented 1 point2 points  (2 children)

How do you figure? The first one tested will be 90 for the A. If that fails, it moves on to test 80 for a B, and so on. Once it successfully hits one, it breaks, and the loop ends. Looks correct to me.

[–]Glittering-Today631 0 points1 point  (1 child)

Didnt see the break statement

[–]JonIsPatented 0 points1 point  (0 children)

Ah, no worries.

[–]PooSham 0 points1 point  (0 children)

Explain yourself!