Current section

Files

Jump to
zipnotic src zipnotic.gleam
Raw

src/zipnotic.gleam

import gleam/list
import gleam/option.{type Option, None, Some}
// -------------------- zip 2
/// Zips two lists into tuples containing optional values. Zipping ends when all
/// lists are exhausted.
///
/// zip_longest_2([1], ["a", "b"]) -> [#(Some(1), Some("a")), #(None, Some("b"))]
pub fn zip_longest_2(
list: List(a),
other: List(b),
) -> List(#(Option(a), Option(b))) {
do_zip_longest_2(list, other, [])
}
fn do_zip_longest_2(
list: List(a),
other: List(b),
acc: List(#(Option(a), Option(b))),
) -> List(#(Option(a), Option(b))) {
case pop(list), pop(other) {
#(None, _), #(None, _) -> acc |> list.reverse
#(a, a_rest), #(b, b_rest) ->
do_zip_longest_2(a_rest, b_rest, [#(a, b), ..acc])
}
}
/// Zips two lists into tuples of values. Zipping ends when the shortest list is
/// exhausted.
///
/// zip_2([1, 2], ["a"]) -> [#(1, "a")]
pub fn zip_2(list: List(a), other: List(b)) -> List(#(a, b)) {
list |> list.zip(other)
}
/// Zips two lists into a result. If the lists are all equal in length, a list
/// of tuples is returned within `Ok`. If the lists are not the same length,
/// `Error(Nil)` is returned.
///
/// strict_zip_2([1], ["a"]) -> Ok([#(1, "a")])
/// strict_zip_2([1, 2], ["a"]) -> Error(Nil)
pub fn strict_zip_2(list: List(a), other: List(b)) -> Result(List(#(a, b)), Nil) {
list |> list.strict_zip(other)
}
// -------------------- zip 3
/// Zips three lists into tuples containing optional values. Zipping ends when
/// all lists are exhausted.
///
/// zip_longest_3([1], ["a", "b"], [True]) -> [#(Some(1), Some("a"), Some(True)), #(None, Some("b"), None)]
pub fn zip_longest_3(
list: List(a),
other_1: List(b),
other_2: List(c),
) -> List(#(Option(a), Option(b), Option(c))) {
do_zip_longest_3(list, other_1, other_2, [])
}
fn do_zip_longest_3(
list: List(a),
other_1: List(b),
other_2: List(c),
acc: List(#(Option(a), Option(b), Option(c))),
) -> List(#(Option(a), Option(b), Option(c))) {
case pop(list), pop(other_1), pop(other_2) {
#(None, _), #(None, _), #(None, _) -> acc |> list.reverse
#(a, a_rest), #(b, b_rest), #(c, c_rest) ->
do_zip_longest_3(a_rest, b_rest, c_rest, [#(a, b, c), ..acc])
}
}
/// Zips three lists into tuples of values. Zipping ends when the shortest list
/// is exhausted.
///
/// zip_3([1], ["a", "b"], [1.0, 1.1]) -> [#(1, "a", 1.0)]
pub fn zip_3(
list: List(a),
other_1: List(b),
other_2: List(c),
) -> List(#(a, b, c)) {
do_zip_3(list, other_1, other_2, [])
}
fn do_zip_3(
list: List(a),
other_1: List(b),
other_2: List(c),
acc: List(#(a, b, c)),
) -> List(#(a, b, c)) {
case list, other_1, other_2 {
[a, ..a_rest], [b, ..b_rest], [c, ..c_rest] ->
do_zip_3(a_rest, b_rest, c_rest, [#(a, b, c), ..acc])
_, _, _ -> acc |> list.reverse
}
}
/// Zips three lists into a result. If the lists are all equal in length, a list
/// of tuples is returned within `Ok`. If the lists are not the same length,
/// `Error(Nil)` is returned.
///
/// strict_zip_3([1], ["a"], [1.0]) -> Ok([#(1, "a", 1.0)])
/// strict_zip_3([1, 2], ["a"], [1.0]) -> Error(Nil)
pub fn strict_zip_3(
list: List(a),
other_1: List(b),
other_2: List(c),
) -> Result(List(#(a, b, c)), Nil) {
do_strict_zip_3(list, other_1, other_2, [])
}
fn do_strict_zip_3(
list: List(a),
other_1: List(b),
other_2: List(c),
acc: List(#(a, b, c)),
) -> Result(List(#(a, b, c)), Nil) {
case list, other_1, other_2 {
[], [], [] -> Ok(acc |> list.reverse)
[], _, _ | _, [], _ | _, _, [] -> Error(Nil)
[a, ..a_rest], [b, ..b_rest], [c, ..c_rest] ->
do_strict_zip_3(a_rest, b_rest, c_rest, [#(a, b, c), ..acc])
}
}
// -------------------- zip 4
/// Zips four lists into tuples containing optional values. Zipping ends when
/// all lists are exhausted.
///
/// zip_longest_4([1], ["a", "b"], [1.0], [True, False]) -> [#(Some(1), Some("a"), Some(1.0), Some(True)), #(None, Some("b"), None, Some(False))]
pub fn zip_longest_4(
list: List(a),
other_1: List(b),
other_2: List(c),
other_3: List(d),
) -> List(#(Option(a), Option(b), Option(c), Option(d))) {
do_zip_longest_4(list, other_1, other_2, other_3, [])
}
fn do_zip_longest_4(
list: List(a),
other_1: List(b),
other_2: List(c),
other_3: List(d),
acc: List(#(Option(a), Option(b), Option(c), Option(d))),
) -> List(#(Option(a), Option(b), Option(c), Option(d))) {
case pop(list), pop(other_1), pop(other_2), pop(other_3) {
#(None, _), #(None, _), #(None, _), #(None, _) -> acc |> list.reverse
#(a, a_rest), #(b, b_rest), #(c, c_rest), #(d, d_rest) ->
do_zip_longest_4(a_rest, b_rest, c_rest, d_rest, [#(a, b, c, d), ..acc])
}
}
/// Zips four lists into tuples of values. Zipping ends when the shortest list
/// is exhausted.
///
/// zip_4([1], ["a", "b"], [1.0], [True, False]) -> [#(1, "a", 1.0, True)]
pub fn zip_4(
list: List(a),
other_1: List(b),
other_2: List(c),
other_3: List(d),
) -> List(#(a, b, c, d)) {
do_zip_4(list, other_1, other_2, other_3, [])
}
fn do_zip_4(
list: List(a),
other_1: List(b),
other_2: List(c),
other_3: List(d),
acc: List(#(a, b, c, d)),
) -> List(#(a, b, c, d)) {
case list, other_1, other_2, other_3 {
[a, ..a_rest], [b, ..b_rest], [c, ..c_rest], [d, ..d_rest] ->
do_zip_4(a_rest, b_rest, c_rest, d_rest, [#(a, b, c, d), ..acc])
_, _, _, _ -> acc |> list.reverse
}
}
/// Zips four lists into a result. If the lists are all equal in length, a list
/// of tuples is returned within `Ok`. If the lists are not the same length,
/// `Error(Nil)` is returned.
///
/// strict_zip_4([1], ["a"], [1.0], [True]) -> Ok([#(1, "a", 1.0, True)])
/// strict_zip_4([1, 2], ["a"], [1.0], [True]) -> Error(Nil)
pub fn strict_zip_4(
list: List(a),
other_1: List(b),
other_2: List(c),
other_3: List(d),
) -> Result(List(#(a, b, c, d)), Nil) {
do_strict_zip_4(list, other_1, other_2, other_3, [])
}
fn do_strict_zip_4(
list: List(a),
other_1: List(b),
other_2: List(c),
other_3: List(d),
acc: List(#(a, b, c, d)),
) -> Result(List(#(a, b, c, d)), Nil) {
case list, other_1, other_2, other_3 {
[], [], [], [] -> Ok(acc |> list.reverse)
[], _, _, _ | _, [], _, _ | _, _, [], _ | _, _, _, [] -> Error(Nil)
[a, ..a_rest], [b, ..b_rest], [c, ..c_rest], [d, ..d_rest] ->
do_strict_zip_4(a_rest, b_rest, c_rest, d_rest, [#(a, b, c, d), ..acc])
}
}
@internal
pub fn pop(list: List(a)) -> #(Option(a), List(a)) {
case list {
[] -> #(None, [])
[a, ..rest] -> #(Some(a), rest)
}
}