aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Saxton <peterhsaxton@gmail.com>2020-06-22 15:17:37 +0100
committerLouis Pilfold <louis@lpil.uk>2020-06-22 20:15:00 +0100
commite4cf585c6a19b813d06658a3dc4dce7968ae3621 (patch)
tree7bd36c7bc30d2477b4d2c1f3b13b2d757942c13b
parentea3a318c0d6c133c8c05d9fa20a7adddc500ad75 (diff)
downloadgleam_stdlib-e4cf585c6a19b813d06658a3dc4dce7968ae3621.tar.gz
gleam_stdlib-e4cf585c6a19b813d06658a3dc4dce7968ae3621.zip
Add pop utility functions for lists
-rw-r--r--src/gleam/list.gleam97
-rw-r--r--test/gleam/list_test.gleam33
2 files changed, 130 insertions, 0 deletions
diff --git a/src/gleam/list.gleam b/src/gleam/list.gleam
index de04d2c..9957e1a 100644
--- a/src/gleam/list.gleam
+++ b/src/gleam/list.gleam
@@ -869,3 +869,100 @@ pub fn key_find(
},
)
}
+
+fn do_pop(haystack, predicate, checked) {
+ case haystack {
+ [] -> Error(Nil)
+ [x, ..rest] -> case predicate(x) {
+ True -> Ok(tuple(x, append(reverse(checked), rest)))
+ False -> do_pop(rest, predicate, [x, ..checked])
+ }
+ }
+}
+
+/// Remove the first element in a given list for which the predicate funtion returns `True`.
+///
+/// Returns `Error(Nil)` if no the function does not return True for any of the
+/// elements.
+///
+/// ## Examples
+///
+/// > pop([1, 2, 3], fn(x) { x > 2 })
+/// Ok(tuple(3, [1, 2]))
+///
+/// > pop([1, 2, 3], fn(x) { x > 4 })
+/// Error(Nil)
+///
+/// > pop([], fn(x) { True })
+/// Error(Nil)
+///
+pub fn pop(
+ in haystack: List(a),
+ one_that is_desired: fn(a) -> Bool,
+) -> Result(tuple(a, List(a)), Nil) {
+ do_pop(haystack, is_desired, [])
+}
+
+fn do_pop_map(haystack, mapper, checked) {
+ case haystack {
+ [] -> Error(Nil)
+ [x, ..rest] -> case mapper(x) {
+ Ok(y) -> Ok(tuple(y, append(reverse(checked), rest)))
+ Error(_) -> do_pop_map(rest, mapper, [x, ..checked])
+ }
+ }
+}
+
+/// Removes the first element in a given list for which the given function returns
+/// `Ok(new_value)` and return the new value as well as list with the value removed.
+///
+/// Returns `Error(Nil)` if no the function does not return Ok for any of the
+/// elements.
+///
+/// ## Examples
+///
+/// > pop_map([[], [2], [3]], head)
+/// Ok(tuple(2, [[], [3]]))
+///
+/// > pop_map([[], []], head)
+/// Error(Nil)
+///
+/// > pop_map([], head)
+/// Error(Nil)
+///
+pub fn pop_map(
+ in haystack: List(a),
+ one_that is_desired: fn(a) -> Result(b, c),
+) -> Result(tuple(b, List(a)), Nil) {
+ do_pop_map(haystack, is_desired, [])
+}
+
+/// Given a list of 2 element tuples, find the first tuple that has a given
+/// key as the first element. This function will return the second element
+/// of the found tuple and list with tuple removed.
+///
+/// If no tuple is found with the given key then `Error(Nil)` is returned.
+///
+/// ## Examples
+///
+/// > key_pop([tuple("a", 0), tuple("b", 1)], "a")
+/// Ok(tuple(0, [tuple("b", 1))
+///
+/// > key_pop([tuple("a", 0), tuple("b", 1)], "b")
+/// Ok(tuple(1, [tuple("a", 0))
+///
+/// > key_pop([tuple("a", 0), tuple("b", 1)], "c")
+/// Error(Nil)
+///
+pub fn key_pop(haystack, key) {
+ pop_map(
+ haystack,
+ fn(entry) {
+ let tuple(k, v) = entry
+ case k {
+ k if k == key -> Ok(v)
+ _ -> Error(Nil)
+ }
+ },
+ )
+}
diff --git a/test/gleam/list_test.gleam b/test/gleam/list_test.gleam
index 35e5701..ef096f6 100644
--- a/test/gleam/list_test.gleam
+++ b/test/gleam/list_test.gleam
@@ -424,3 +424,36 @@ pub fn key_find_test() {
|> list.key_find(2)
|> should.equal(Error(Nil))
}
+
+pub fn pop_test() {
+ list.pop([1, 2, 3], fn(x) { x > 2 })
+ |> should.equal(Ok(tuple(3, [1, 2])))
+
+ list.pop([1, 2, 3], fn(x) { x > 4 })
+ |> should.equal(Error(Nil))
+
+ list.pop([], fn(_x) { True })
+ |> should.equal(Error(Nil))
+}
+
+pub fn pop_map_test() {
+ list.pop_map(["foo", "2", "3"], int.parse)
+ |> should.equal(Ok(tuple(2, ["foo", "3"])))
+
+ list.pop_map(["foo", "bar"], int.parse)
+ |> should.equal(Error(Nil))
+
+ list.pop_map([], int.parse)
+ |> should.equal(Error(Nil))
+}
+
+pub fn key_pop_test() {
+ list.key_pop([tuple("a", 0), tuple("b", 1)], "a")
+ |> should.equal(Ok(tuple(0, [tuple("b", 1)])))
+
+ list.key_pop([tuple("a", 0), tuple("b", 1)], "b")
+ |> should.equal(Ok(tuple(1, [tuple("a", 0)])))
+
+ list.key_pop([tuple("a", 0), tuple("b", 1)], "c")
+ |> should.equal(Error(Nil))
+}