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

ozans-playlist concept exercise #265

Open
wants to merge 3 commits 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
12 changes: 12 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,18 @@
"prerequisites": [],
"status": "wip"
},
{
"slug": "ozans-playlist",
"name": "Ozans Playlist",
"uuid": "323ff052-9238-4299-944c-c231c939ff9f",
"concepts": [
"set-operations"
],
"prerequisites": [
"vectors"
],
"status": "wip"
},
{
"slug": "cars-assemble",
"name": "Cars, Assemble",
Expand Down
1 change: 1 addition & 0 deletions exercises/concept/ozans-playlist/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Hints
86 changes: 86 additions & 0 deletions exercises/concept/ozans-playlist/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Instructions

Ozan is putting together a playlist for an upcoming roadtrip. He doesn"t want to hear the same track more than once, but the playlist has gotten so long that he"s having trouble remembering which tracks have already been added.

The API for Ozan"s music player only knows how to work with vectors. No explicit loops or if/else logic are possible. He needs your help!

## 1. Remove duplicate tracks

Implement the `remove_duplicates` function, which takes a playlist as a _parameter_ and _returns_ a new playlist where all the tracks are unique.

```R
> playlist <- c(
"Court and Spark - Joni Mitchell",
"Big Yellow Taxi - Joni Mitchell",
"Court and Spark - Joni Mitchell"
)

> remove_duplicates(playlist)
[1] "Court and Spark - Joni Mitchell" "Big Yellow Taxi - Joni Mitchell"
```

## 2. Check whether a track has already been added

Implement the `has_track` function, which takes a playlist and a track as _parameters_ and _returns_ a boolean that indicates whether the playlist contains the track.

```R
> playlist <- c(
"The Fashion Show - Grace Jones",
"Dr. Funkenstein - Parliament"
)

> has_track(playlist, "Dr. Funkenstein - Parliament")
[1] TRUE

> has_track(playlist, "Walking in the Rain - Grace Jones")
[1] FALSE
```

## 3. Add tracks

Implement the `add_tracks` function, which takes a playlist and a vector of one or more tracks as _parameters_ and _returns_ a new playlist that includes the tracks.

```R
> playlist <- c("Selma - Bijelo Dugme")

> playlist <- add_tracks(playlist, "Atomic Dog - George Clinton")
> playlist
[1] "Selma - Bijelo Dugme" "Atomic Dog - George Clinton"

> add_tracks(playlist, "Selma - Bijelo Dugme")
[1] "Selma - Bijelo Dugme" "Atomic Dog - George Clinton"

> add_tracks(playlist, c("The Chain - Fleetwood Mac", "Selma - Bijelo Dugme"))
[1] "Selma - Bijelo Dugme" "Atomic Dog - George Clinton" "The Chain - Fleetwood Mac"

```

## 4. Delete tracks

Implement the `delete_tracks` function, which takes a playlist and one or more tracks as _parameters_ and _returns_ a new playlist that does not include the tracks.

```R
> playlist <- c(
"The Treasure - Fra Lippo Lippi",
"After the Fall - Klaus Nomi"
)

> playlist <- delete_tracks(playlist, "The Treasure - Fra Lippo Lippi")
> playlist
[1] "After the Fall - Klaus Nomi"

> delete_tracks(playlist, "I Feel the Magic - Belinda Carlisle")
[1] "After the Fall - Klaus Nomi"
```

## 5. Compare playlists

Ozan meets a new friend and wonders how similar their tastes are.
Implement the `find_common_tracks` function, which takes two playlists and returns a new playlist containing only tracks present in both.

```R
> playlist_1 <- c("Karma - Taylor Swift", "Tired - Adele")
> playlist_2 <- c("Andromeda - Weyes Blood", "Karma - Taylor Swift")
> find_common_tracks(playlist_1, playlist_2)
[1] "Karma - Taylor Swift"
````
13 changes: 13 additions & 0 deletions exercises/concept/ozans-playlist/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Introduction

R has no separate Set datatype, instead using a variety of functions to perform similar operations on vectors.

We have already seen `%in%` to test for set membership:

```R
2 %in% 1:10 # TRUE
12 %in% 1:10 # FALSE
```

Relevant functions include `unique` (to remove duplicates), `union()`, `intersect()` and `setdiff()` to operate on pairs of sets.
Details are available online.
11 changes: 11 additions & 0 deletions exercises/concept/ozans-playlist/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"authors": ["colinleach"],
"contributors": [],
"files": {
"solution": ["ozans-playlist.R"],
"test": ["test_ozans-playlist.R"],
"exemplar": [".meta/exemplar.R"]
},
"forked_from": ["javascript/ozans-playlist"],
"blurb": "Use set operations to manage a playlist"
}
24 changes: 24 additions & 0 deletions exercises/concept/ozans-playlist/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Design

## Goal

The goal of this exercise is to introduce basic set operations in R.

## Learning objectives

- Understand that base R uses vectors for set operations, with no dediicated class.
- Understand the use of `%in%`, `unique()`, `union()`, `intersect()` and `setdiff()`.

## Out of scope

- Use of the `hashtable` package, though this is mentioned in `set-operations/about.md` which unlocks on completing this exercise.

## Concepts

The Concepts this exercise unlocks are:

- None.

## Prerequisites

- `vectors`
19 changes: 19 additions & 0 deletions exercises/concept/ozans-playlist/.meta/exemplar.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
remove_duplicates <- function(playlist) {
unique(playlist)
}

has_track <- function(playlist, track) {
track %in% playlist
}

add_tracks <- function(playlist, tracks) {
union(playlist, tracks)
}

delete_tracks <- function(playlist, tracks) {
setdiff(playlist, tracks)
}

find_common_tracks <- function(playlist_1, playlist_2) {
intersect(playlist_1, playlist_2)
}
14 changes: 14 additions & 0 deletions exercises/concept/ozans-playlist/ozans-playlist.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
remove_duplicates <- function(playlist) {
}

has_track <- function(playlist, track) {
}

add_tracks <- function(playlist, tracks) {
}

delete_tracks <- function(playlist, tracks) {
}

find_common_tracks <- function(playlist_1, playlist_2) {
}
110 changes: 110 additions & 0 deletions exercises/concept/ozans-playlist/test_ozans-playlist.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
source("./ozans-playlist.R")
library(testthat)

# 1) remove_duplicates

test_that("works for a non-empty playlist", {
track_1 <- "Two Paintings and a Drum - Carl Cox"
track_2 <- "Leash Called Love - The Sugarcubes"
playlist <- c(track_1, track_2, track_1)
expected <- c(track_1, track_2)
expect_equal(remove_duplicates(playlist), expected)
})

test_that("works for an empty playlist", {
playlist <- c()
expected <- c()
expect_equal(remove_duplicates(playlist), expected)
})

# 2) has_track

test_that("returns true when the track is in the playlist", {
track_1 <- "Big Science - Laurie Anderson"
track_2 <- "Tightrope - Laurie Anderson"
playlist <- c(track_1, track_2)
expect_equal(has_track(playlist, track_1), TRUE)
})

test_that("returns false when the track is not in the playlist", {
track_1 <- "Big Science - Laurie Anderson"
track_2 <- "Tightrope - Laurie Anderson"
playlist <- c(track_2)
expect_equal(has_track(playlist, track_1), FALSE)
})

# 3) add_tracks

test_that("adds tracks that are not already in the playlist", {
track_1 <- "Jigsaw Feeling - Siouxsie and the Banshees"
track_2 <- "Feeling Good - Nina Simone"
playlist <- c()
expected <- c(track_1)
expect_equal(add_tracks(playlist, track_1), expected)
})

test_that("does not add a track that is already in the playlist", {
track_1 <- "Jigsaw Feeling - Siouxsie and the Banshees"
track_2 <- "Feeling Good - Nina Simone"
playlist <- c(track_1, track_2)
expected <- c(track_1, track_2)
expect_equal(add_tracks(playlist, track_1), expected)
})

test_that("add multiple tracks, some already in the playlist", {
track_1 <- "Jigsaw Feeling - Siouxsie and the Banshees"
track_2 <- "Feeling Good - Nina Simone"
track_3 <- "I Was an Eagle - Laura Marling"
playlist <- c(track_1, track_2)
expected <- c(track_1, track_2, track_3)
expect_equal(add_tracks(playlist, c(track_1, track_3)), expected)
})

# 4) delete_tracks

test_that("works if the track is present in the playlist", {
track_1 <- "Ancestors - Tanya Tagaq"
track_2 <- "Take This Hammer - Lead Belly"
playlist <- c(track_1, track_2)
expected <- c(track_2)
expect_equal(delete_tracks(playlist, track_1), expected)
})

test_that("works if the track is not present in the playlist", {
track_1 <- "Ancestors - Tanya Tagaq"
track_2 <- "Take This Hammer - Lead Belly"
playlist <- c(track_2)
expected <- c(track_2)
expect_equal(delete_tracks(playlist, track_1), expected)
})

test_that("works for multiple tracks if some present in the playlist", {
track_1 <- "Ancestors - Tanya Tagaq"
track_2 <- "Take This Hammer - Lead Belly"
track_3 <- "With Or Without You - U2"
playlist <- c(track_1, track_2)
expected <- c(track_2)
expect_equal(delete_tracks(playlist, c(track_1, track_3)), expected)
})

# 5) find_common_tracks

test_that("works when there is partial overlap", {
track_1 <- "Ancestors - Tanya Tagaq"
track_2 <- "Take This Hammer - Lead Belly"
track_3 <- "With Or Without You - U2"
playlist_1 <- c(track_1, track_2)
playlist_2 <- c(track_2, track_3)
expected <- c(track_2)
expect_equal(find_common_tracks(playlist_1, playlist_2), expected)
})

test_that("works when there nothing in common", {
track_1 <- "Paranoid - Black Sabbath"
track_2 <- "Overkill - Motörhead"
track_3 <- "Gurre-Lieder - Schönberg"
track_4 <- "Gymnopédies - Satie"
playlist_1 <- c(track_1, track_2)
playlist_2 <- c(track_3, track_4)
expect_equal(length(find_common_tracks(playlist_1, playlist_2)), 0)
})