-
-
Notifications
You must be signed in to change notification settings - Fork 159
Add map and reduce concepts #595
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
Open
JaumeAmoresDS
wants to merge
11
commits into
exercism:main
Choose a base branch
from
JaumeAmoresDS:concept/map_reduce
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 6 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
183cbc2
Added map and reduce concepts
JaumeAmoresDS 60acd2d
Made about.md be the same as introduction.md
JaumeAmoresDS 67f7cdc
Improved readability of reduce introduction.md
JaumeAmoresDS 9faba51
Improved readability of map
JaumeAmoresDS 6e8d9e1
Removed mentions to more advanced concepts
JaumeAmoresDS f439364
Reduced contents of introduction.md
JaumeAmoresDS c6588e7
Apply suggestions from code review
JaumeAmoresDS 871b3e9
Update about.md
JaumeAmoresDS 41eb197
Update introduction.md
JaumeAmoresDS b159677
Update about.md
JaumeAmoresDS f240a08
Update introduction.md
JaumeAmoresDS 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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "blurb": "We provide here a basic explanation about the map higher-order function and its most common usage.", | ||
| "authors": ["JaumeAmoresDS"] | ||
| } | ||
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,35 @@ | ||
| # Introduction | ||
|
|
||
| In its most basic form, the higher-order function `map` accepts two arguments: a function `f` and a sequence of elements `s`. It then applies `f` to each element of the sequence, and returns a list where the i-th element is the result of applying `f` to the i-th element of `s`: | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```clojure | ||
| (map inc [1 2 3]) ; => (2 3 4) | ||
| ``` | ||
|
|
||
| The previous example applies function `inc`, which increases a number by one, to each element of the vector `[1 2 3]`, and returns the result of this application as a list `(2 3 4)`, where each element is the result of applying `inc` to the corresponding element of [1 2 3]. | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Let's see another example where we greet a given person with the message "Welcome": | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```clojure | ||
| (defn say-welcome | ||
| [name] | ||
| (str "Welcome " name "!")) | ||
|
|
||
| (map say-welcome ["Chris" "Jane" "Peter"]) ; => ("Welcome Chris!" "Welcome Jane!" "Welcome Peter!") | ||
| ``` | ||
|
|
||
| ## Returning a lazy sequence | ||
|
|
||
| Previously we provided a simplified explanation of how `map` operates. In reality, `map` returns a so-called *lazy* sequence. Although an explanation of lazy sequences goes beyond the scope of this introduction, it basically means that the elements of the resulting list are not generated until they are actually needed. In other words, it is not until we actually use elements of this list (e.g., to print them or retrieve their value) that the function `f` passed to `map` is applied to generate each element. This is advantageous when `f` is computationally expensive and we end-up only needing to retrieve some of the elements of the resulting list later in the program. | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## Using multiple collections | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| `map` allows multiple collections to be passed as input. If the number of collections we pass is `n`, the function `f` will receive `n` elements, one for each collection in the list. The result is a list where the i-th element is obtained by applying `f` to the i-th element of each collection: | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```clojure | ||
| (def coll_a [a1 a2]) | ||
| (def coll_b [b1 b2]) | ||
| (def coll_c [c1 c2]) | ||
| (map f coll_a coll_b coll_c) ; => ((f a1 b1 c1) (f a2 b2 c2)) | ||
| ``` | ||
|
|
||
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,19 @@ | ||
| # Introduction | ||
|
|
||
| In its most basic form, the higher-order function `map` accepts two arguments: a function `f` and a sequence of elements `s`. It then applies `f` to each element of the sequence, and returns a list where the i-th element is the result of applying `f` to the i-th element of `s`: | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```clojure | ||
| (map inc [1 2 3]) ; => (2 3 4) | ||
| ``` | ||
|
|
||
| The previous example applies function `inc`, which increases a number by one, to each element of the vector `[1 2 3]`, and returns the result of this application as a list `(2 3 4)`, where each element is the result of applying `inc` to the corresponding element of [1 2 3]. | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| Let's see another example where we greet a given person with the message "Welcome": | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```clojure | ||
| (defn say-welcome | ||
| [name] | ||
| (str "Welcome " name "!")) | ||
|
|
||
| (map say-welcome ["Chris" "Jane" "Peter"]) ; => ("Welcome Chris!" "Welcome Jane!" "Welcome Peter!") | ||
| ``` | ||
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,10 @@ | ||
| [ | ||
| { | ||
| "url": "https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/map", | ||
| "description": "Clojure API: map" | ||
| }, | ||
| { | ||
| "url": "https://clojure.org/guides/higher_order_functions", | ||
| "description": "Clojure guides: Higher Order Functions" | ||
| } | ||
| ] | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
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,4 @@ | ||
| { | ||
| "blurb": "We provide here a basic explanation about the reduce higher-order function and its most common usage.", | ||
| "authors": ["JaumeAmoresDS"] | ||
| } | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
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,57 @@ | ||
| # Introduction | ||
|
|
||
| The higher-order funcion `reduce` accepts either two or three arguments. When called with three arguments, `(reduce f val coll)` applies the function `f` to `val` and the first element `x_1` of the collection `coll`: `(f val x_1)`. Then, it applies the function `f` to its own result and the second element `x_2` of the collection `coll`: `(f (f val x_1) x_2)`. Then again, it applies `f` to its previous result and the third element of `coll`, and so on until all the elements of `coll` are used. Let's see a typical example using `+` as our function: | ||
|
|
||
| ```clojure | ||
| (reduce + 100 [1 2 3 4]) | ||
| ;=> (+ 100 1) | ||
| ;=> (+ 101 2) | ||
| ;=> (+ 103 3) | ||
| ;=> (+ 106 4) | ||
| ;=> 110 | ||
| ``` | ||
|
|
||
| When called with only two arguments, `(reduce f coll)` applies the function `f` to the two first elements `x_1` and `x_2` of the collection `coll`, then applies `f` to its own result and the third element `x_3` of `coll`, then again to its own result and the fourth element of `coll`, and so on until all the elements of `coll` are used: | ||
|
|
||
| ```clojure | ||
| (reduce + [1 2 3 4]) | ||
| ;=> (+ 1 2) | ||
| ;=> (+ 3 3) | ||
| ;=> (+ 6 4) | ||
| ;=> 10 | ||
| ``` | ||
|
|
||
| In all these cases, the function `f` must accept either two arguments or a variable number of arguments as happens in the previous case with function `+`. Let's see an example with a user-defined function: | ||
|
|
||
| ```clojure | ||
| (defn include-if-even | ||
| [coll x] | ||
| (if (= (mod x 2) 0) | ||
| (conj coll x) | ||
| coll)) | ||
| ``` | ||
|
|
||
| In the previous example, the function `include-if-even` accepts two arguments: a collection `coll` and a number `x`. It then checks if `x` module 2 is 0, in which case `x` is an even number. If that's the case, it includes this number into the collection `coll` and returns this collection. Otherwise, it returns the original collection. We can then apply `reduce` to collect all the even numbers from a given collection as follows: | ||
|
|
||
| ```clojure | ||
| (reduce include-if-even [] [1 2 3 4]) | ||
| ;=> (include-if-even [] 1) | ||
| ;=> (include-if-even [] 2) | ||
| ;=> (include-if-even [2] 3) | ||
| ;=> (include-if-even [2] 4) | ||
| ;=> [2 4] | ||
| ``` | ||
|
|
||
| Note that in the previous example we must necessarily pass three arguments to `reduce`: our function `include-if-even`, an initial collection `[]`, and a collection of numbers like `[1 2 3 4]`. The initial collection `[]` is necessary due to the fact that `include-if-even` needs it as its first argument. | ||
|
|
||
| ## Especial cases | ||
|
|
||
| Especial cases arise when we use an empty collection or a collection with only one item: | ||
|
|
||
| - If we apply `reduce` to an empty collection, `(reduce f val coll)` returns `(f val)`, and `(reduce f coll)` returns the result of applying `f` with no arguments. In this case, the function `f` must be able to use no arguments. | ||
| - If we apply `reduce` to a collection with only one item, `(reduce f val coll)` returns `(f val x_1)`, i.e., the result of applying `f` to `val` and the first element `x_1` of `coll`. If used with only two arguments, `(f coll)` returns the only element found in `coll`, and `f` is not called. | ||
|
|
||
| ## Using collections of functions | ||
|
|
||
| `reduce` accepts any type of collection, including one that contains functions. In that case, we will typically use three arguments `(reduce f val coll)`, and the function `f` applies the first function `g_1` from the collection to `val`, then the second function `g_2` to the result of the previous application, `(f (f val g_1) g_2)` and so on until all the functions are applied. | ||
|
|
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,45 @@ | ||
| # Introduction | ||
|
|
||
| The higher-order funcion `reduce` accepts either two or three arguments. When called with three arguments, `(reduce f val coll)` applies the function `f` to `val` and the first element `x_1` of the collection `coll`: `(f val x_1)`. Then, it applies the function `f` to its own result and the second element `x_2` of the collection `coll`: `(f (f val x_1) x_2)`. Then again, it applies `f` to its previous result and the third element of `coll`, and so on until all the elements of `coll` are used. Let's see a typical example using `+` as our function: | ||
|
|
||
| ```clojure | ||
| (reduce + 100 [1 2 3 4]) | ||
| ;=> (+ 100 1) | ||
| ;=> (+ 101 2) | ||
| ;=> (+ 103 3) | ||
| ;=> (+ 106 4) | ||
| ;=> 110 | ||
| ``` | ||
|
|
||
| When called with only two arguments, `(reduce f coll)` applies the function `f` to the two first elements `x_1` and `x_2` of the collection `coll`, then applies `f` to its own result and the third element `x_3` of `coll`, then again to its own result and the fourth element of `coll`, and so on until all the elements of `coll` are used: | ||
|
|
||
| ```clojure | ||
| (reduce + [1 2 3 4]) | ||
| ;=> (+ 1 2) | ||
| ;=> (+ 3 3) | ||
| ;=> (+ 6 4) | ||
| ;=> 10 | ||
| ``` | ||
|
|
||
| In all these cases, the function `f` must accept either two arguments or a variable number of arguments as happens in the previous case with function `+`. Let's see an example with a user-defined function: | ||
|
|
||
| ```clojure | ||
| (defn include-if-even | ||
| [coll x] | ||
| (if (= (mod x 2) 0) | ||
| (conj coll x) | ||
| coll)) | ||
| ``` | ||
|
|
||
| In the previous example, the function `include-if-even` accepts two arguments: a collection `coll` and a number `x`. It then checks if `x` module 2 is 0, in which case `x` is an even number. If that's the case, it includes this number into the collection `coll` and returns this collection. Otherwise, it returns the original collection. We can then apply `reduce` to collect all the even numbers from a given collection as follows: | ||
|
|
||
| ```clojure | ||
| (reduce include-if-even [] [1 2 3 4]) | ||
| ;=> (include-if-even [] 1) | ||
| ;=> (include-if-even [] 2) | ||
| ;=> (include-if-even [2] 3) | ||
| ;=> (include-if-even [2] 4) | ||
| ;=> [2 4] | ||
| ``` | ||
|
|
||
| Note that in the previous example we must necessarily pass three arguments to `reduce`: our function `include-if-even`, an initial collection `[]`, and a collection of numbers like `[1 2 3 4]`. The initial collection `[]` is necessary due to the fact that `include-if-even` needs it as its first argument. |
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,26 @@ | ||
| [ | ||
| { | ||
| "url": "https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/partial", | ||
| "description": "Clojure API: partial" | ||
| }, | ||
| { | ||
| "url": "https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/comp", | ||
| "description": "Clojure API: comp" | ||
| }, | ||
| { | ||
| "url": "https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/comp", | ||
| "description": "Clojure API: comp" | ||
| }, | ||
| { | ||
| "url": "https://clojuredocs.org/clojure.core/memoize", | ||
| "description": "Clojure docs: memoize" | ||
| }, | ||
| { | ||
| "url": "https://clojuredocs.org/clojure.core/juxt", | ||
| "description": "Clojure docs: juxt" | ||
| }, | ||
| { | ||
| "url": "https://clojure.org/guides/higher_order_functions", | ||
| "description": "Clojure guides: Higher Order Functions" | ||
| } | ||
| ] | ||
JaumeAmoresDS marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
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
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.
Uh oh!
There was an error while loading. Please reload this page.