-
-
Notifications
You must be signed in to change notification settings - Fork 93
list-ops: create exercise #376
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
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
32b2631
WIP: list-ops: create exercise
glennj 95b4213
tweak
glennj 278a55c
Library tests can be simpler using the setup func
glennj db3d133
list-ops: add example, stub, readme, hints; freshen tests
glennj 9e608d6
typos
glennj 194f9da
list-ops: rework for v3 directory structure
glennj 65a0a2c
list-ops: uses namerefs that require bash 4.3
glennj 5e0f27e
gha PR script handles .meta directory gracefully
glennj cc32120
gha filename does not begin with "./"
glennj b89a19b
simplify filename handling
glennj File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# Library of Functions | ||
|
||
This is the first exercise we've seen where the solution we're writing | ||
is not a "main" script. We're writing a library to be "source"d into | ||
other scripts that will invoke our functions. | ||
|
||
## Bash namerefs | ||
|
||
This exercise requires the use of `nameref` variables. This requires a bash | ||
version of at least 4.0. If you're using the default bash on MacOS, you'll | ||
need to install another version: see [Installing Bash](https://exercism.io/tracks/bash/installation) | ||
|
||
Namerefs are a way to pass a variable to a function _by reference_. That | ||
way, the variable can be modified in the function and the updated value is | ||
available in the calling scope. Here's an example: | ||
```bash | ||
prependElements() { | ||
local -n __array=$1 | ||
shift | ||
__array=( "$@" "${__array[@]}" ) | ||
} | ||
|
||
my_array=( a b c ) | ||
echo "before: ${my_array[*]}" # => before: a b c | ||
|
||
prependElements my_array d e f | ||
echo "after: ${my_array[*]}" # => after: d e f a b c | ||
``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Instructions | ||
|
||
Implement basic list operations. | ||
|
||
In functional languages list operations like `length`, `map`, and | ||
`reduce` are very common. Implement a series of basic list operations, | ||
without using existing functions. | ||
|
||
The precise number and names of the operations to be implemented will be | ||
track dependent to avoid conflicts with existing names, but the general | ||
operations you will implement include: | ||
|
||
* `append` (*given two lists, add all items in the second list to the end of the first list*); | ||
* `concatenate` (*given a series of lists, combine all items in all lists into one flattened list*); | ||
* `filter` (*given a predicate and a list, return the list of all items for which `predicate(item)` is True*); | ||
* `length` (*given a list, return the total number of items within it*); | ||
* `map` (*given a function and a list, return the list of the results of applying `function(item)` on all items*); | ||
* `foldl` (*given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left using `function(accumulator, item)`*); | ||
* `foldr` (*given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right using `function(item, accumulator)`*); | ||
* `reverse` (*given a list, return a list with all the original items, but in reversed order*); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"authors": [], | ||
"files": { | ||
"solution": ["list_ops.sh"], | ||
"test": ["list_ops_test.sh"], | ||
"example": [".meta/example.sh"] | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
#!/usr/bin/env bash | ||
|
||
bash_version=$((10 * BASH_VERSINFO[0] + BASH_VERSINFO[1])) | ||
if (( bash_version < 43 )); then | ||
echo "This library requires at least bash version 4.3" >&2 | ||
return 4 | ||
fi | ||
|
||
# Due to inherent bash limitations around word splitting and globbing, | ||
# functions that are intended to *return a list* are instead required to | ||
# receive a nameref parameter, the name of an array variable that will be | ||
# populated in the list function. | ||
# See the filter, map and reverse functions. | ||
|
||
# Also note that nameref parameters cannot have the same name as the | ||
# name of the variable in the calling scope. | ||
|
||
|
||
# Append some elements to the given list. | ||
list::append () { | ||
local -n __list1=$1 | ||
shift | ||
__list1+=( "$@" ) | ||
} | ||
|
||
# Return only the list elements that pass the given function. | ||
list::filter () { | ||
local funcname=$1 | ||
local -n __list=$2 | ||
local -n __result=$3 | ||
|
||
for element in "${__list[@]}"; do | ||
$funcname "$element" && __result+=("$element") | ||
done | ||
} | ||
|
||
# Transform the list elements, using the given function, | ||
# into a new list. | ||
list::map () { | ||
local funcname=$1 | ||
local -n __list=$2 | ||
local -n __result=$3 | ||
|
||
for element in "${__list[@]}"; do | ||
__result+=( "$($funcname "$element")" ) | ||
done | ||
} | ||
|
||
# Left-fold the list using the function and the initial value. | ||
list::foldl () { | ||
local funcname=$1 acc=$2 | ||
local -n __list=$3 | ||
|
||
for element in "${__list[@]}"; do | ||
acc=$( $funcname "$acc" "$element" ) | ||
done | ||
echo "$acc" | ||
} | ||
|
||
# Right-fold the list using the function and the initial value. | ||
list::foldr () { | ||
local funcname=$1 acc=$2 | ||
local -n __list=$3 | ||
|
||
for (( i = ${#__list[@]} - 1; i >=0; i-- )); do | ||
acc=$( $funcname "${__list[i]}" "$acc" ) | ||
done | ||
echo "$acc" | ||
} | ||
|
||
# Return the list reversed | ||
list::reverse () { | ||
local -n __list=$1 | ||
local -n __result=$2 | ||
local -i size=${#__list[@]} | ||
for (( i = 0; i < size; i++ )); do | ||
__result[i]=${__list[-1 - i]} | ||
done | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
[canonical-tests] | ||
|
||
# empty lists | ||
"485b9452-bf94-40f7-a3db-c3cf4850066a" = true | ||
|
||
# list to empty list | ||
"2c894696-b609-4569-b149-8672134d340a" = true | ||
|
||
# empty list to list | ||
"e842efed-3bf6-4295-b371-4d67a4fdf19c" = true | ||
|
||
# non-empty lists | ||
"71dcf5eb-73ae-4a0e-b744-a52ee387922f" = true | ||
|
||
# empty list | ||
"28444355-201b-4af2-a2f6-5550227bde21" = false | ||
|
||
# list of lists | ||
"331451c1-9573-42a1-9869-2d06e3b389a9" = false | ||
|
||
# list of nested lists | ||
"d6ecd72c-197f-40c3-89a4-aa1f45827e09" = false | ||
|
||
# empty list | ||
"0524fba8-3e0f-4531-ad2b-f7a43da86a16" = true | ||
|
||
# non-empty list | ||
"88494bd5-f520-4edb-8631-88e415b62d24" = true | ||
|
||
# empty list | ||
"1cf0b92d-8d96-41d5-9c21-7b3c37cb6aad" = false | ||
|
||
# non-empty list | ||
"d7b8d2d9-2d16-44c4-9a19-6e5f237cb71e" = false | ||
|
||
# empty list | ||
"c0bc8962-30e2-4bec-9ae4-668b8ecd75aa" = true | ||
|
||
# non-empty list | ||
"11e71a95-e78b-4909-b8e4-60cdcaec0e91" = true | ||
|
||
# empty list | ||
"613b20b7-1873-4070-a3a6-70ae5f50d7cc" = false | ||
|
||
# direction independent function applied to non-empty list | ||
"e56df3eb-9405-416a-b13a-aabb4c3b5194" = false | ||
|
||
# direction dependent function applied to non-empty list | ||
"d2cf5644-aee1-4dfc-9b88-06896676fe27" = false | ||
|
||
# empty list | ||
"36549237-f765-4a4c-bfd9-5d3a8f7b07d2" = true | ||
|
||
# direction independent function applied to non-empty list | ||
"7a626a3c-03ec-42bc-9840-53f280e13067" = true | ||
|
||
# direction dependent function applied to non-empty list | ||
"d7fcad99-e88e-40e1-a539-4c519681f390" = true | ||
|
||
# empty list | ||
"aeb576b9-118e-4a57-a451-db49fac20fdc" = false | ||
|
||
# direction independent function applied to non-empty list | ||
"c4b64e58-313e-4c47-9c68-7764964efb8e" = false | ||
|
||
# direction dependent function applied to non-empty list | ||
"be396a53-c074-4db3-8dd6-f7ed003cce7c" = false | ||
|
||
# empty list | ||
"17214edb-20ba-42fc-bda8-000a5ab525b0" = true | ||
|
||
# direction independent function applied to non-empty list | ||
"e1c64db7-9253-4a3d-a7c4-5273b9e2a1bd" = true | ||
|
||
# direction dependent function applied to non-empty list | ||
"8066003b-f2ff-437e-9103-66e6df474844" = true | ||
|
||
# empty list | ||
"94231515-050e-4841-943d-d4488ab4ee30" = true | ||
|
||
# non-empty list | ||
"fcc03d1e-42e0-4712-b689-d54ad761f360" = true | ||
|
||
# list of lists is not flattened | ||
"40872990-b5b8-4cb8-9085-d91fc0d05d26" = false |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
#!/usr/bin/env bash | ||
|
||
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then | ||
echo "This library of functions should be sourced into another script" >&2 | ||
exit 4 | ||
fi | ||
bash_version=$((10 * BASH_VERSINFO[0] + BASH_VERSINFO[1])) | ||
if (( bash_version < 43 )); then | ||
echo "This library requires at least bash version 4.3" >&2 | ||
return 4 | ||
fi | ||
|
||
# Due to inherent bash limitations around word splitting and globbing, | ||
# functions that are intended to *return a list* are instead required to | ||
# receive a nameref parameter, the name of an array variable that will be | ||
# populated in the list function. | ||
# See the filter, map and reverse functions. | ||
|
||
# Also note that nameref parameters cannot have the same name as the | ||
# name of the variable in the calling scope. | ||
|
||
|
||
# Append some elements to the given list. | ||
list::append () { | ||
echo "Implement me" >&2 | ||
return 1 | ||
} | ||
|
||
# Return only the list elements that pass the given function. | ||
list::filter () { | ||
echo "Implement me" >&2 | ||
return 1 | ||
} | ||
|
||
# Transform the list elements, using the given function, | ||
# into a new list. | ||
list::map () { | ||
echo "Implement me" >&2 | ||
return 1 | ||
} | ||
|
||
# Left-fold the list using the function and the initial value. | ||
list::foldl () { | ||
echo "Implement me" >&2 | ||
return 1 | ||
} | ||
|
||
# Right-fold the list using the function and the initial value. | ||
list::foldr () { | ||
echo "Implement me" >&2 | ||
return 1 | ||
} | ||
|
||
# Return the list reversed | ||
list::reverse () { | ||
echo "Implement me" >&2 | ||
return 1 | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this sufficient to talk about "libraries"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is, and if not, we will find out about it from students.