diff options
-rw-r--r-- | src/gleam/iterator.gleam | 43 | ||||
-rw-r--r-- | test/gleam/iterator_test.gleam | 19 |
2 files changed, 62 insertions, 0 deletions
diff --git a/src/gleam/iterator.gleam b/src/gleam/iterator.gleam index 746fbc8..c51e336 100644 --- a/src/gleam/iterator.gleam +++ b/src/gleam/iterator.gleam @@ -567,6 +567,49 @@ pub fn filter( |> Iterator } +fn do_filter_map( + continuation: fn() -> Action(a), + f: fn(a) -> Result(b, c), +) -> Action(b) { + case continuation() { + Stop -> Stop + Continue(e, next) -> + case f(e) { + Ok(e) -> Continue(e, fn() { do_filter_map(next, f) }) + Error(_) -> do_filter_map(next, f) + } + } +} + +/// Creates an iterator from an existing iterator and a transforming predicate function. +/// +/// The new iterator will contain elements from the first iterator for which +/// the given function returns `Ok`, transformed to the value inside the `Ok`. +/// +/// This function does not evaluate the elements of the iterator, the +/// computation is performed when the iterator is later run. +/// +/// ## Examples +/// +/// ```gleam +/// import gleam/string +/// import gleam/int +/// "a1b2c3d4e5f" +/// |> string.to_graphemes +/// |> from_list +/// |> filter_map(int.parse) +/// |> to_list +/// // -> [1, 2, 3, 4, 5] +/// ``` +/// +pub fn filter_map( + iterator: Iterator(a), + keeping_with f: fn(a) -> Result(b, c), +) -> Iterator(b) { + fn() { do_filter_map(iterator.continuation, f) } + |> Iterator +} + /// Creates an iterator that repeats a given iterator infinitely. /// /// ## Examples diff --git a/test/gleam/iterator_test.gleam b/test/gleam/iterator_test.gleam index 189f283..bc024a9 100644 --- a/test/gleam/iterator_test.gleam +++ b/test/gleam/iterator_test.gleam @@ -2,6 +2,7 @@ import gleam/iterator.{Done, Next} import gleam/list import gleam/dict import gleam/should +import gleam/int // a |> from_list |> to_list == a pub fn to_from_list_test() { @@ -272,6 +273,24 @@ pub fn filter_test() { testcase([1, 2, 3, 4, 5, 6], even) } +pub fn filter_map_test() { + let testcase = fn(subject, f) { + subject + |> iterator.from_list + |> iterator.filter_map(f) + |> iterator.to_list + |> should.equal(list.filter_map(subject, f)) + } + + testcase([], int.parse) + testcase(["1"], int.parse) + testcase(["1", "2", "3"], int.parse) + testcase(["1", "a", "b"], int.parse) + testcase(["l", "2", "3", "a"], int.parse) + testcase(["1", "c", "3", "a", "b"], int.parse) + testcase(["1", "20", "ten", "4", "5", "69"], int.parse) +} + pub fn repeat_test() { 1 |> iterator.repeat |