Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

name-badges concept exercise #271

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,19 @@
"booleans"
],
"status": "wip"
},
{
"slug": "name-badges",
"name": "Name Badges",
"uuid": "31f8973a-5035-4b54-9670-e589fa59361b",
"concepts": [
"nothingness"
],
"prerequisites": [
"vector-filtering",
"strings"
],
"status": "wip"
}
],
"practice": [
Expand Down
1 change: 1 addition & 0 deletions exercises/concept/name-badges/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Hints
54 changes: 54 additions & 0 deletions exercises/concept/name-badges/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Instructions

In this exercise you'll be writing code to print name badges for factory employees. Employees have an ID, name, and department name. Employee badge labels are formatted as follows: `"[id] - name - DEPARTMENT"`.

## 1. Print a badge for an employee

Implement the `print_name_badge` function. It should take an ID, name, and a department. It should return the badge label, with the department name in uppercase.

```R
print_name_badge(67, "Katherine Williams", "Strategic Communication")
# => "[67] - Katherine Williams - STRATEGIC COMMUNICATION"
```

## 2. Print a badge for a new employee

Due to a quirk in the computer system, new employees occasionally don't yet have an ID when they start working at the factory. As badges are required, they will receive a temporary badge without the ID prefix.

Extend the `print_name_badge` function. When the id is missing, it should print a badge without it.

```R
print_name_badge(NA, "Robert Johnson", "Procurement")
# => "Robert Johnson - PROCUREMENT"
```

## 3. Print a badge for the owner

Even the factory's owner has to wear a badge at all times. However, an owner does not have a department and never will: he is above all the departments. In this case, the label should print `"OWNER"` instead of the department name.

Extend the `print_name_badge` function. When the department is `NULL`, assume the badge belongs to the company owner.

```R
print_name_badge(204, "Rachel Miller", NULL)
# => "[204] - Rachel Miller - OWNER"
```

Note that it is possible for the owner to also be a new employee.

```R
print_name_badge(NA, "Rachel Miller", NULL)
# => "Rachel Miller - OWNER"
```

## 4. Calculate the total salary of emplyees with no ID

As a rough metric of how well the IDs are being issued, you want to see the combined salary of employees with no ID. A high value means lots are waiting, or the problem is affecting senior people: both bad.

Implement the `salaries_no_id` function that takes a vector of IDs and a corresponding vector of salaries, and returns the sum of salaries for people with no ID yet. Both vectors are the same length.

```R
ids <- c(204, NA, 210, 352, NA, 263)
salaries <- c(23, 21, 47, 35, 17, 101) * 1000
salaries_no_id(ids, salaries)
# => 38,000
```
39 changes: 39 additions & 0 deletions exercises/concept/name-badges/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Introduction

Many languages have a way such as `null` or `none` to indicate a non-existent value.
Because R is designed to handle large volumes of (often messy) data, it has multiple forms of nothingness.

The overall aim is to flag missing or suspect values as they are encountered, then continue without raising an exception.

## NULL

If a value really doesn't exist, it is repesented by `NULL`. This is probably closest to what C or Python might do.

```R
> v <- c() # zero-length vector
> v
NULL
> is.null(v)
[1] TRUE
```

In many contexts, `NULL` values are simply ignored:

```R
> c(2, 3, NULL, 5)
[1] 2 3 5
```

## NA

For situations where a value exists but we don't know what it is, `NA` is used. For example, when counting vehicles traveling on a road, human observers might go off sick or automatic sensors break down, but the traffic continues to flow.

```R
> v <- c(1, 2, NA, 4, 5)
> v
[1] 1 2 NA 4 5
> is.na(v) # test for data gaps
[1] FALSE FALSE TRUE FALSE FALSE
```

Thus `NA` is a placeholder, warning humans that they need to make a decision about how to handle this.
11 changes: 11 additions & 0 deletions exercises/concept/name-badges/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"authors": ["colinleach"],
"contributors": [],
"files": {
"solution": ["name-badges.R"],
"test": ["test_name-badges.R"],
"exemplar": [".meta/exemplar.R"]
},
"forked_from": ["elixir/name-badge"],
"blurb": "Handle missing values in employee name badges"
}
26 changes: 26 additions & 0 deletions exercises/concept/name-badges/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Design

## Goal

The goal of this exercise is to teach the student about the various forms of nothingness in R.

## Learning objectives

- Understand `NULL` as the absence of a value.
- Understand `NA` as a placeholder for a missing value.
- Understand the basics of how to test for and respond to these values.
- Understand that R tries to flag these values in-place *without* throwing an exception: a data-science approach rather than a computer-science approach.

## Out of scope

- `NaN` and `Inf` as flagging invalid numbers, though this is mentioned in the concept's `about.md`. Omitting these is purely pragmatic, with no obvious way to include them in the exercise.
- The greater importance of this concept in more complex structures such as `dataframes`. At this stage, the discussion is limited to vectors.

## Concepts

- `errors`

## Prerequisites

- `vector-filtering`
- `strings`
11 changes: 11 additions & 0 deletions exercises/concept/name-badges/.meta/exemplar.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
print_name_badge <- function(id, name, department) {
dept <- ifelse(is.null(department), "OWNER", toupper(department))
if (is.na(id)) {
return(sprintf("%s - %s", name, dept))
}
sprintf("[%d] - %s - %s", id, name, dept)
}

salaries_no_id <- function(ids, salaries) {
sum(salaries[is.na(ids)])
}
5 changes: 5 additions & 0 deletions exercises/concept/name-badges/name-badges.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
print_name_badge <- function(id, name, department) {
}

salaries_no_id <- function(ids, salaries) {
}
58 changes: 58 additions & 0 deletions exercises/concept/name-badges/test_name-badges.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
source("./name-badges.R")
library(testthat)

# 1) print_name_badge

test_that("prints the employee badge with full data", {
id <- 455
name <- "Mary M. Brown"
department <- "MARKETING"
expected <- "[455] - Mary M. Brown - MARKETING"
expect_equal(print_name_badge(id, name, department), expected)
})

test_that("uppercases the department", {
id <- 89
name <- "Jack McGregor"
department <- "Procurement"
expected <- "[89] - Jack McGregor - PROCUREMENT"
expect_equal(print_name_badge(id, name, department), expected)
})

test_that("prints the employee badge without id", {
id <- NA
name <- "Barbara White"
department <- "SECURITY"
expected <- "Barbara White - SECURITY"
expect_equal(print_name_badge(id, name, department), expected)
})

test_that("prints the owner badge", {
id <- 1
name <- "Anna Johnson"
department <- NULL
expected <- "[1] - Anna Johnson - OWNER"
expect_equal(print_name_badge(id, name, department), expected)
})

test_that("prints the owner badge without id", {
id <- NA
name <- "Stephen Dann"
department <- NULL
expected <- "Stephen Dann - OWNER"
expect_equal(print_name_badge(id, name, department), expected)
})

# salaries_no_id

test_that("sums salaries for employees without ID", {
ids <- c(201, 217, NA, 352, 102, NA, 263)
salaries <- c(19, 23, 42, 29, 65, 122, 54)
expect_equal(salaries_no_id(ids, salaries), 164)
})

test_that("sums salaries but no employees without ID", {
ids <- c(201, 217, 47, 352, 102, 163, 263)
salaries <- c(25, 27, 44, 26, 63, 122, 34)
expect_equal(salaries_no_id(ids, salaries), 0)
})