From bd139951d535afc3f56f2e4cf06ec83566c8bdaf Mon Sep 17 00:00:00 2001 From: colinleach Date: Sat, 8 Jul 2023 10:35:05 -0700 Subject: [PATCH 1/2] elyses-analytic-enchantments concept exercise --- config.json | 12 +++ .../.docs/hints.md | 1 + .../.docs/instructions.md | 65 +++++++++++++++ .../.docs/introduction.md | 60 ++++++++++++++ .../.meta/config.json | 11 +++ .../.meta/design.md | 25 ++++++ .../.meta/exemplar.R | 25 ++++++ .../elyses-analytic-enchantments.R | 17 ++++ .../test_elyses-analytic-enchantments.R | 80 +++++++++++++++++++ 9 files changed, 296 insertions(+) create mode 100644 exercises/concept/elyses-analytic-enchantments/.docs/hints.md create mode 100644 exercises/concept/elyses-analytic-enchantments/.docs/instructions.md create mode 100644 exercises/concept/elyses-analytic-enchantments/.docs/introduction.md create mode 100644 exercises/concept/elyses-analytic-enchantments/.meta/config.json create mode 100644 exercises/concept/elyses-analytic-enchantments/.meta/design.md create mode 100644 exercises/concept/elyses-analytic-enchantments/.meta/exemplar.R create mode 100644 exercises/concept/elyses-analytic-enchantments/elyses-analytic-enchantments.R create mode 100644 exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R diff --git a/config.json b/config.json index 312e341d..c8fdef1a 100644 --- a/config.json +++ b/config.json @@ -41,6 +41,18 @@ "concepts": ["basics"], "prerequisites": [], "status": "wip" + }, + { + "slug": "elyses-analytic-enchantments", + "name": "Elyses Analytic Enchantments", + "uuid": "2d6c9880-efce-4e57-8abf-d702087b6082", + "concepts": [ + "vector-filtering" + ], + "prerequisites": [ + "vectors" + ], + "status": "wip" } ], "practice": [ diff --git a/exercises/concept/elyses-analytic-enchantments/.docs/hints.md b/exercises/concept/elyses-analytic-enchantments/.docs/hints.md new file mode 100644 index 00000000..b5296c36 --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/.docs/hints.md @@ -0,0 +1 @@ +# Hints diff --git a/exercises/concept/elyses-analytic-enchantments/.docs/instructions.md b/exercises/concept/elyses-analytic-enchantments/.docs/instructions.md new file mode 100644 index 00000000..ea5e5805 --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/.docs/instructions.md @@ -0,0 +1,65 @@ +# Instructions +# +Elyse, magician-to-be, continues her training. She will be given several stacks of cards that she needs to perform her tricks. +To make things a bit easier, she only uses the cards 1 to 10. + +In this exercise, use built-in methods to analyse the contents of a vector. + +## 1. Determine if a card is present + +Elyse wants to determine if a card is present in the stack -- in other words, if the stack contains a specific number. + +```R +card = 3; +does_stack_include_card(c(2, 3, 4, 5), card); +# => TRUE +``` + +## 2. Find the position of a card + +Elyse wants to know the position (index) of a card in the stack. +If the card is not in the stack, return `-1`. + +```R +card = 2; +get_card_position(c(9, 7, 3, 2), card); +# => 4 +``` + +## 3. Determine if each card is even + +Elyse wants to know if every card is even -- in other words, if each number in the stack is an even number. + +```R +is_each_card_even(c(2, 4, 6, 7)); +# => FALSE +``` + +## 4. Check if the stack contains an odd-value card + +Elyse wants to know if there is an odd number in the stack. + +```R +does_stack_include_odd_card(c(3, 2, 6, 4, 8)); +# => TRUE +``` + +## 5. Get the first odd card from the stack + +Elyse wants to know the value of the first card that is odd. +If there is no odd card in the stack, return `-1`. + +```R +get_first_odd_card(c(4, 2, 8, 7, 9)); +# => 7 +``` + +## 6. Determine the position of the first card that is even + +Elyse wants to know the position of the first card that is even. +If there is no even card in the stack, return `-1`. + +```R +get_first_even_card_position(c(5, 2, 3, 1)); +# => 2 +``` \ No newline at end of file diff --git a/exercises/concept/elyses-analytic-enchantments/.docs/introduction.md b/exercises/concept/elyses-analytic-enchantments/.docs/introduction.md new file mode 100644 index 00000000..9e785423 --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/.docs/introduction.md @@ -0,0 +1,60 @@ +# Introduction + +We saw in the `vectors` concept that a vector can be used in a conditional expression, giving a vector of booleans. This in turn can be used in functions such as `all()` and `any()`. + +```R +> v <- c(4, 7, 10) +> v >= 6 +[1] FALSE TRUE TRUE +> all(v > 6) +[1] FALSE # not all elements match this condition +> any(v > 6) +[1] TRUE # at least one element matches +``` + +The technique is much more powerful than this. + +## Array subsets + +Selected elements of an array can be pulled out with an index number or a vector of indices: + +```R +> v <- 5:10 +> v +[1] 5 6 7 8 9 10 +> v[3] +[1] 7 +> v[c(2, 4)] +[1] 6 8 +``` + +Alternatively, use a vector of booleans to filter the original vector, returning a subset of entries matched to a `TRUE` value: + +```R +> v <- 1:3 +> bools <- c(FALSE, TRUE, TRUE) +> v[bools] +[1] 2 3 +``` + +It is a small step from there to generating the boolean vector with a conditional expression: + +```R +> v[v >= 2] +[1] 2 3 +``` + +## Finding indices + +The `which()` function takes a boolean argument and returns a vector of indices that yield `TRUE`. + +```R +> v +[1] 2 7 9 + +> v[v > 5] # returns values +[1] 7 9 + +> which(v > 5) # returns indices +[1] 2 3 +``` diff --git a/exercises/concept/elyses-analytic-enchantments/.meta/config.json b/exercises/concept/elyses-analytic-enchantments/.meta/config.json new file mode 100644 index 00000000..01874e9f --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/.meta/config.json @@ -0,0 +1,11 @@ +{ + "authors": ["colinleach"], + "contributors": [], + "files": { + "solution": ["elyses-analytic-enchantments.R"], + "test": ["test_elyses-analytic-enchantments.R"], + "exemplar": [".meta/exemplar.R"] + }, + "forked_from": ["javascript/elyses-analytic-enchantments"], + "blurb": "Explore vector filtering as you help Elyse continue her training as a magician" +} diff --git a/exercises/concept/elyses-analytic-enchantments/.meta/design.md b/exercises/concept/elyses-analytic-enchantments/.meta/design.md new file mode 100644 index 00000000..68e66bd7 --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/.meta/design.md @@ -0,0 +1,25 @@ +# Design + +## Goal + +The goal of this exercise is to build on the `vectors` concept by teaching the student more about vector filtering/subsetting in R. + +## Learning objectives + +- Understand the use of conditional expressions to get a subset of the original vector. +- Understand the use of `which()` to get indices of elements that match a condition. + +## Out of scope + +- Recycling is not mentioned within this exercise, though it is explained in `vector-filtering/about.md` which unlocks on completing this exercise. + +## Concepts + +The Concepts this exercise unlocks are: + +- `vector-functions` +- `nothingness` + +## Prerequisites + +- `vectors` diff --git a/exercises/concept/elyses-analytic-enchantments/.meta/exemplar.R b/exercises/concept/elyses-analytic-enchantments/.meta/exemplar.R new file mode 100644 index 00000000..9132007d --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/.meta/exemplar.R @@ -0,0 +1,25 @@ +does_stack_include_card <- function(stack, card) { + card %in% stack +} + +get_card_position <- function(stack, card) { + ifelse(does_stack_include_card(stack, card), which(stack == card), -1) +} + +is_each_card_even <- function(stack) { + all(stack %% 2 == 0) +} + +does_stack_include_odd_card <- function(stack) { + any(stack %% 2 != 0) +} + +get_first_odd_card <- function(stack) { + odds <- stack[stack %% 2 != 0] + ifelse(length(odds) > 0, odds[1], -1) +} + +get_first_even_card_position <- function(stack) { + even_index <- which(stack %% 2 == 0) + ifelse(length(even_index) > 0, even_index[1], -1) +} diff --git a/exercises/concept/elyses-analytic-enchantments/elyses-analytic-enchantments.R b/exercises/concept/elyses-analytic-enchantments/elyses-analytic-enchantments.R new file mode 100644 index 00000000..27be4bdc --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/elyses-analytic-enchantments.R @@ -0,0 +1,17 @@ +does_stack_include_card <- function(stack, card) { +} + +get_card_position <- function(stack, card) { +} + +is_each_card_even <- function(stack) { +} + +does_stack_include_odd_card <- function(stack) { +} + +get_first_odd_card <- function(stack) { +} + +get_first_even_card_position <- function(stack) { +} diff --git a/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R b/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R new file mode 100644 index 00000000..55aa880f --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R @@ -0,0 +1,80 @@ +source("./elyses-analytic-enchantments.R") +library(testthat) + +context("elyses-analytic-enchantments") + +# does_stack_include_card + +test_that("when it is the first card", { + stack <- c(1, 2, 3) + card <- 1 + expect_equal(does_stack_include_card(stack, card), TRUE) +}) + +test_that("when there is a card found", { + stack <- c(1, 2, 3) + card <- 4 + expect_equal(does_stack_include_card(stack, card), FALSE) +}) + +# get_card_position + +test_that("when it is the first card", { + stack <- c(1, 2, 3) + card <- 1 + expect_equal(get_card_position(stack, card), 1) +}) + +test_that("when the card is not found", { + stack <- c(1, 2, 3) + card <- 4 + expect_equal(get_card_position(stack, card), -1) +}) + +# is_each_card_even + +test_that("when all cards are even", { + stack <- c(2, 4, 6) + expect_equal(is_each_card_even(stack), TRUE) +}) + +test_that("when any card is odd", { + stack <- c(2, 5, 6) + expect_equal(is_each_card_even(stack), FALSE) +}) + +# does_stack_include_odd_card + +test_that("should be true if odd number card is found", { + stack <- c(2, 5, 6) + expect_equal(does_stack_include_odd_card(stack), TRUE) +}) + +test_that("should be false if no odd number card is found", { + stack <- c(2, 4, 6) + expect_equal(does_stack_include_odd_card(stack), FALSE) +}) + +# get_first_odd_card + +test_that("should return the first odd card found", { + stack <- c(2, 4, 1, 3) + expect_equal(get_first_odd_card(stack), 1) +}) + +test_that("should return -1 if odd card is not found", { + stack <- c(4, 2, 6) + expect_equal(get_first_odd_card(stack), -1) +}) + +# get_first_even_card_position + +test_that("should return position of first even card", { + stack <- c(2, 4, 1, 3) + expect_equal(get_first_even_card_position(stack), 1) +}) + +test_that("should return -1 when the card is not found", { + stack <- c(1, 3, 5) + expect_equal(get_first_even_card_position(stack), -1) +}) From 305fc4cc83a85071d1c5bd39d91efdc72c601c51 Mon Sep 17 00:00:00 2001 From: colinleach Date: Sun, 9 Jul 2023 13:55:00 -0700 Subject: [PATCH 2/2] removed context() line --- .../test_elyses-analytic-enchantments.R | 2 -- 1 file changed, 2 deletions(-) diff --git a/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R b/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R index 55aa880f..44d9a56a 100644 --- a/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R +++ b/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R @@ -1,8 +1,6 @@ source("./elyses-analytic-enchantments.R") library(testthat) -context("elyses-analytic-enchantments") - # does_stack_include_card test_that("when it is the first card", {