aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gleam/iterator.gleam43
-rw-r--r--test/gleam/iterator_test.gleam19
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