diff options
author | Robert Attard <robert.attard@mail.mcgill.ca> | 2022-01-03 18:51:10 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-03 23:51:10 +0000 |
commit | 265c228f4a8f233d863f35df9f8e888918902cdc (patch) | |
tree | c7a6a35939625c1096670d927951379f9b625523 | |
parent | 2c7c5d2a511bd5cb6ed65214790c5a91488dd7e5 (diff) | |
download | gleam_stdlib-265c228f4a8f233d863f35df9f8e888918902cdc.tar.gz gleam_stdlib-265c228f4a8f233d863f35df9f8e888918902cdc.zip |
Int.digits & int.undigits
-rw-r--r-- | .github/workflows/ci.yml | 2 | ||||
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | src/gleam/int.gleam | 59 | ||||
-rw-r--r-- | test/gleam/int_test.gleam | 34 |
4 files changed, 94 insertions, 2 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0bbe10b..919a864 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ jobs: node-version: "16.0.0" - uses: gleam-lang/setup-gleam@v1.0.1 with: - gleam-version: "0.18.0-rc1" + gleam-version: "0.19.0-rc1" - run: gleam test - run: npm test # - run: gleam format --check src test diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d22e46..fda755b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ - The `dynamic.DecodeError` now has a `path` field. - The decoder functions of the `dynamic` module now return multiple errors. - The `dynamic.tuple*` functions are now partially applied. +- The `int` module gains the `digits` and `undigits` functions. ## v0.18.1 - 2021-12-19 diff --git a/src/gleam/int.gleam b/src/gleam/int.gleam index a9dff63..2aff67f 100644 --- a/src/gleam/int.gleam +++ b/src/gleam/int.gleam @@ -62,7 +62,7 @@ if javascript { "../gleam_stdlib.mjs" "to_string" } -/// For use in `to_base_string` when base is outside of the allowed range. +/// Error value when trying to operate with a base out of the allowed range. pub type InvalidBase { InvalidBase } @@ -323,3 +323,60 @@ fn do_product(numbers: List(Int), initial: Int) -> Int { [x, ..rest] -> do_product(rest, x * initial) } } + +/// Splits an integer into its digit representation in the specified base +/// +/// ## Examples +/// +/// > digits(234, 10) +/// Ok([2,3,4]) +/// +/// > digits(234, 1) +/// Error(InvalidBase) +/// +pub fn digits(number: Int, base: Int) -> Result(List(Int), InvalidBase) { + case base < 2 { + True -> Error(InvalidBase) + False -> Ok(do_digits(number, base, [])) + } +} + +fn do_digits(number: Int, base: Int, acc: List(Int)) -> List(Int) { + case absolute_value(number) < base { + True -> [number, ..acc] + False -> do_digits(number / base, base, [number % base, ..acc]) + } +} + +/// Joins a list of digits into a single value. +/// Returns an error if the base is less than 2 or if the list contains a digit greater than or equal to the specified base. +/// +/// ## Examples +/// +/// > undigits([2,3,4], 10) +/// Ok(234) +/// +/// > undigits([2,3,4], 1) +/// Error(InvalidBase) +/// +/// > undigits([2,3,4], 2) +/// Error(InvalidBase) +/// +pub fn undigits(numbers: List(Int), base: Int) -> Result(Int, InvalidBase) { + case base < 2 { + True -> Error(InvalidBase) + False -> do_undigits(numbers, base, 0) + } +} + +fn do_undigits( + numbers: List(Int), + base: Int, + acc: Int, +) -> Result(Int, InvalidBase) { + case numbers { + [] -> Ok(acc) + [digit, .._rest] if digit >= base -> Error(InvalidBase) + [digit, ..rest] -> do_undigits(rest, base, acc * base + digit) + } +} diff --git a/test/gleam/int_test.gleam b/test/gleam/int_test.gleam index 07832dd..1fbc102 100644 --- a/test/gleam/int_test.gleam +++ b/test/gleam/int_test.gleam @@ -282,3 +282,37 @@ pub fn product_test() { int.product([1, 2, 3]) |> should.equal(6) } + +pub fn digits_test() { + int.digits(123, 10) + |> should.equal(Ok([1, 2, 3])) + + int.digits(-123, 10) + |> should.equal(Ok([-1, -2, -3])) + + int.digits(123, 2) + |> should.equal(Ok([1, 1, 1, 1, 0, 1, 1])) + + int.digits(123, 1) + |> should.equal(Error(int.InvalidBase)) +} + +pub fn undigits_test() { + int.undigits([], 10) + |> should.equal(Ok(0)) + + int.undigits([1, 2, 3], 10) + |> should.equal(Ok(123)) + + int.undigits([-1, -2, -3], 10) + |> should.equal(Ok(-123)) + + int.undigits([1, 1, 1, 1, 0, 1, 1], 2) + |> should.equal(Ok(123)) + + int.undigits([1, 2, 3], 1) + |> should.equal(Error(int.InvalidBase)) + + int.undigits([1, 1, 2], 2) + |> should.equal(Error(int.InvalidBase)) +} |