diff --git a/config.json b/config.json index b51aafcc..3abad491 100644 --- a/config.json +++ b/config.json @@ -66,6 +66,18 @@ "prerequisites": [], "status": "wip" }, + { + "slug": "elyses-analytic-enchantments", + "name": "Elyses Analytic Enchantments", + "uuid": "2d6c9880-efce-4e57-8abf-d702087b6082", + "concepts": [ + "vector-filtering" + ], + "prerequisites": [ + "vectors" + ], + "status": "wip" + }, { "slug": "cars-assemble", "name": "Cars, Assemble", 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..44d9a56a --- /dev/null +++ b/exercises/concept/elyses-analytic-enchantments/test_elyses-analytic-enchantments.R @@ -0,0 +1,78 @@ +source("./elyses-analytic-enchantments.R") +library(testthat) + +# 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) +})