diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eac17d7..08fbf85c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ - The `debug` function in the `io` module has been deprecated in favour of the `echo` keyword. -- The performance of `string.append` and `string.concat` have been improved. +- The performance of `string.append`, `string.join`, and `string.concat` have + been improved. ## v0.58.0 - 2025-03-23 diff --git a/src/gleam/string.gleam b/src/gleam/string.gleam index fe52a640..64b65a52 100644 --- a/src/gleam/string.gleam +++ b/src/gleam/string.gleam @@ -432,11 +432,23 @@ fn repeat_loop(string: String, times: Int, acc: String) -> String { /// // -> "home/evan/Desktop" /// ``` /// -@external(javascript, "../gleam_stdlib.mjs", "join") pub fn join(strings: List(String), with separator: String) -> String { - strings - |> list.intersperse(with: separator) - |> concat + case strings { + [] -> "" + [first, ..rest] -> join_loop(rest, separator, first) + } +} + +fn join_loop( + strings: List(String), + separator: String, + accumulator: String, +) -> String { + case strings { + [] -> accumulator + [string, ..strings] -> + join_loop(strings, separator, accumulator <> separator <> string) + } } /// Pads the start of a `String` until it has a given length. diff --git a/src/gleam_stdlib.mjs b/src/gleam_stdlib.mjs index 8068c9eb..b0feabff 100644 --- a/src/gleam_stdlib.mjs +++ b/src/gleam_stdlib.mjs @@ -205,17 +205,6 @@ export function split(xs, pattern) { return List.fromArray(xs.split(pattern)); } -export function join(xs, separator) { - const iterator = xs[Symbol.iterator](); - let result = iterator.next().value || ""; - let current = iterator.next(); - while (!current.done) { - result = result + separator + current.value; - current = iterator.next(); - } - return result; -} - export function concat(xs) { let result = ""; for (const x of xs) { diff --git a/test/gleam/string_test.gleam b/test/gleam/string_test.gleam index df326b61..f2d63c30 100644 --- a/test/gleam/string_test.gleam +++ b/test/gleam/string_test.gleam @@ -161,7 +161,27 @@ pub fn repeat_test() { |> should.equal("") } -pub fn join_test() { +pub fn join_0_test() { + [] + |> string.join(with: ", ") + |> should.equal("") + + [] + |> string.join(with: "-") + |> should.equal("") +} + +pub fn join_1_test() { + ["Hello"] + |> string.join(with: ", ") + |> should.equal("Hello") + + ["Hello"] + |> string.join(with: "-") + |> should.equal("Hello") +} + +pub fn join_2_test() { ["Hello", "world!"] |> string.join(with: ", ") |> should.equal("Hello, world!") @@ -171,6 +191,16 @@ pub fn join_test() { |> should.equal("Hello-world!") } +pub fn join_3_test() { + ["Hello", "there", "world!"] + |> string.join(with: ", ") + |> should.equal("Hello, there, world!") + + ["Hello", "there", "world!"] + |> string.join(with: "-") + |> should.equal("Hello-there-world!") +} + pub fn trim_test() { " hats \n" |> string.trim