Zig Project: Grade Tracker
A grade tracker is a program that turns a list of scores into a summary. This project reports the average, the highest and lowest scores, the pass count, and a letter band.
An average function over a slice
The function adds every score in the slice, then divides by the count. The five scores sum to 361, and 361 divided by 5 is 72.2.
const std = @import("std");
fn average(scores: []const i32) f64 {
var sum: i32 = 0;
for (scores) |s| {
sum += s;
}
const sum_f: f64 = @floatFromInt(sum);
const count_f: f64 = @floatFromInt(scores.len);
return sum_f / count_f;
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
const scores = [_]i32{ 72, 85, 49, 91, 64 };
const avg = average(&scores);
try out.print("Average: {d:.1}\n", .{avg});
}Highest, lowest, and pass count in one loop
One loop tracks the largest and smallest scores seen so far. It also counts each score of 60 or more as a pass.
const std = @import("std");
pub fn main() !void {
const out = std.io.getStdOut().writer();
const scores = [_]i32{ 72, 85, 49, 91, 64 };
var highest = scores[0];
var lowest = scores[0];
var passes: i32 = 0;
for (scores) |s| {
if (s > highest) {
highest = s;
}
if (s < lowest) {
lowest = s;
}
if (s >= 60) {
passes += 1;
}
}
try out.print("Highest: {d}\n", .{highest});
try out.print("Lowest: {d}\n", .{lowest});
try out.print("Passes: {d}\n", .{passes});
}A switch turns a score into a band letter
The band function matches the score against ranges, highest first. A score of 91 lands in the top range, and 49 falls through to the else prong.
const std = @import("std");
fn band(score: i32) u8 {
return switch (score) {
90...100 => 'A',
80...89 => 'B',
70...79 => 'C',
60...69 => 'D',
else => 'F',
};
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
try out.print("91 earns {c}\n", .{band(91)});
try out.print("49 earns {c}\n", .{band(49)});
}Example
const std = @import("std");
fn average(scores: []const i32) f64 {
var sum: i32 = 0;
for (scores) |s| {
sum += s;
}
const sum_f: f64 = @floatFromInt(sum);
const count_f: f64 = @floatFromInt(scores.len);
return sum_f / count_f;
}
fn band(score: i32) u8 {
return switch (score) {
90...100 => 'A',
80...89 => 'B',
70...79 => 'C',
60...69 => 'D',
else => 'F',
};
}
pub fn main() !void {
const out = std.io.getStdOut().writer();
var scores = [_]i32{ 72, 85, 49, 91, 64 };
std.mem.sort(i32, &scores, {}, comptime std.sort.asc(i32));
try out.print("Scores: {any}\n", .{scores});
const avg = average(&scores);
try out.print("Average: {d:.1}\n", .{avg});
try out.print("Highest: {d}\n", .{scores[scores.len - 1]});
try out.print("Lowest: {d}\n", .{scores[0]});
var passes: i32 = 0;
for (scores) |s| {
if (s >= 60) {
passes += 1;
}
}
try out.print("Passes: {d} of {d}\n", .{ passes, scores.len });
const avg_score: i32 = @intFromFloat(avg);
try out.print("Class band: {c}\n", .{band(avg_score)});
}Key points
- Score list: a fixed array holds every score for one class.
- Average: the sum of the scores divided by how many scores there are.
- Pass: a score of 60 or more counts as a pass.
- Band: a switch turns a score range into a letter such as A or C.
- Sort: std.mem.sort orders the scores, so the first is the lowest and the last is the highest.
In this example, the program sorts the five scores into ascending order and prints them. The average function returns 72.2, printed with one decimal place. The sorted ends give the lowest score, 49, and the highest, 91, and a counting loop finds 4 passes out of 5. The average is converted back to an integer so the band function can grade the class with a C.
Note
the average needs float division, so the integer sum is converted with @floatFromInt before dividing.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
After the scores are sorted in ascending order, where is the highest score?