diff options
author | Vladislav Botvin <darkvlados@gmail.com> | 2024-05-01 13:36:23 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-01 11:36:23 +0100 |
commit | b92e284631cacf0711545445e87241e8d512ed8f (patch) | |
tree | f1db94f9ce698e745cf97bd50178f0bde5329215 | |
parent | bca305d766c9363ff6067be5c43ee94c8ae2e0e4 (diff) | |
download | gleam_stdlib-b92e284631cacf0711545445e87241e8d512ed8f.tar.gz gleam_stdlib-b92e284631cacf0711545445e87241e8d512ed8f.zip |
iterator.find_map (#573)
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | src/gleam/iterator.gleam | 45 | ||||
-rw-r--r-- | test/gleam/iterator_test.gleam | 35 |
3 files changed, 81 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index fdae968..a61e116 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased - The `list` module gains the `wrap` function. +- The `iterator` module gains the `find_map` function. ## v0.37.0 - 2024-04-19 diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam index c5cd0af..bb6be98 100644 --- a/src/gleam/iterator.gleam +++ b/src/gleam/iterator.gleam @@ -712,6 +712,51 @@ pub fn find( |> do_find(is_desired) } +fn do_find_map( + continuation: fn() -> Action(a), + f: fn(a) -> Result(b, c), +) -> Result(b, Nil) { + case continuation() { + Stop -> Error(Nil) + Continue(e, next) -> + case f(e) { + Ok(e) -> Ok(e) + Error(_) -> do_find_map(next, f) + } + } +} + +/// Finds the first element in a given iterator +/// for which the given function returns `Ok(new_value)`, +/// then returns the wrapped `new_value`. +/// +/// Returns `Error(Nil)` if no such element is found. +/// +/// ## Examples +/// +/// ```gleam +/// find_map(from_list([1, 2, 3]), first) +/// // -> Ok(1) +/// ``` +/// +/// ```gleam +/// find_map(from_list([]), first) +/// // -> Error(Nil) +/// ``` +/// +/// ```gleam +/// find(empty(), first) +/// // -> Error(Nil) +/// ``` +/// +pub fn find_map( + in haystack: Iterator(a), + one_that is_desired: fn(a) -> Result(b, c), +) -> Result(b, Nil) { + haystack.continuation + |> do_find_map(is_desired) +} + fn do_index( continuation: fn() -> Action(element), next: Int, diff --git a/test/gleam/iterator_test.gleam b/test/gleam/iterator_test.gleam index cd58035..186ea69 100644 --- a/test/gleam/iterator_test.gleam +++ b/test/gleam/iterator_test.gleam @@ -376,6 +376,41 @@ pub fn find_test() { |> should.equal(Ok(Cat(id: 10))) } +pub fn find_map_test() { + iterator.range(0, 10) + |> iterator.find_map(fn(e) { + case e == 5 { + True -> Ok(e) + False -> Error(Nil) + } + }) + |> should.equal(Ok(5)) + + iterator.range(0, 10) + |> iterator.find_map(fn(e) { + case e > 10 { + True -> Ok(e) + False -> Error(Nil) + } + }) + |> should.equal(Error(Nil)) + + iterator.empty() + |> iterator.find_map(fn(_x) { Ok(True) }) + |> should.equal(Error(Nil)) + + iterator.unfold(Cat(id: 1), fn(cat: Cat) { + iterator.Next(cat, Cat(id: cat.id + 1)) + }) + |> iterator.find_map(fn(cat: Cat) { + case cat.id == 10 { + True -> Ok(cat) + False -> Error(Nil) + } + }) + |> should.equal(Ok(Cat(id: 10))) +} + pub fn index_test() { iterator.from_list(["a", "b", "c"]) |> iterator.index |