Skip to content

Commit 3d90896

Browse files
committed
Add List.ends_with?/2
1 parent fe2425a commit 3d90896

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This release no longer supports WERL (a graphical user interface for the Erlang
1313
* [Exception] Add `MissingApplicationsError` exception to denote missing applications
1414
* [Kernel] Update source code parsing to match [UTS #55](https://www.unicode.org/reports/tr55/) latest recommendations. In particular, mixed script is allowed in identifiers as long as they are separate by underscores (`_`), such as `http_сервер`. Previously allowed highly restrictive identifiers, which mixed Latin and other scripts, such as the japanese word for t-shirt, `Tシャツ`, now require the underscore as well
1515
* [Kernel] Warn on bidirectional confusability in identifiers
16+
* [List] Add `List.ends_with?/2`
1617
* [Macro] Improve `dbg` handling of `if/2`, `unless/2`, and code blocks
1718
* [Process] Handle arbitrarily high integer values in `Process.sleep/1`
1819
* [String] Inspect special whitespace and zero-width characters using their Unicode representation

lib/elixir/lib/list.ex

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,44 @@ defmodule List do
908908
def starts_with?(list, []) when is_list(list), do: true
909909
def starts_with?(list, [_ | _]) when is_list(list), do: false
910910

911+
@doc """
912+
Returns `true` if `list` ends with the given `suffix` list, otherwise returns `false`.
913+
914+
If `suffix` is an empty list, it returns `true`.
915+
916+
### Examples
917+
918+
iex> List.ends_with?([1, 2, 3], [2, 3])
919+
true
920+
921+
iex> List.ends_with?([1, 2], [1, 2, 3])
922+
false
923+
924+
iex> List.ends_with?([:alpha], [])
925+
true
926+
927+
iex> List.ends_with?([], [:alpha])
928+
false
929+
930+
"""
931+
@doc since: "1.18.0"
932+
@spec ends_with?(nonempty_list, nonempty_list) :: boolean
933+
@spec ends_with?(list, []) :: true
934+
@spec ends_with?([], nonempty_list) :: false
935+
def ends_with?(list, suffix) do
936+
case ends_with_offset(list, suffix) do
937+
nil -> false
938+
n -> :lists.nthtail(n, list) === suffix
939+
end
940+
end
941+
942+
defp ends_with_offset([], [_ | _]), do: nil
943+
defp ends_with_offset(rest, []), do: length(rest)
944+
945+
defp ends_with_offset([_ | tail], [_ | suffix_tail]) do
946+
ends_with_offset(tail, suffix_tail)
947+
end
948+
911949
@doc """
912950
Converts a charlist to an atom.
913951

lib/elixir/test/elixir/list_test.exs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,45 @@ defmodule ListTest do
285285
end
286286
end
287287

288+
describe "ends_with?/2" do
289+
test "list and prefix are equal" do
290+
assert List.ends_with?([], [])
291+
assert List.ends_with?([1], [1])
292+
assert List.ends_with?([1, 2, 3], [1, 2, 3])
293+
end
294+
295+
test "proper lists" do
296+
refute List.ends_with?([2], [1, 2])
297+
assert List.ends_with?([1, 2, 3], [2, 3])
298+
refute List.ends_with?([2, 3, 4], [1, 2, 3, 4])
299+
end
300+
301+
test "list is empty" do
302+
refute List.ends_with?([], [1])
303+
refute List.ends_with?([], [1, 2])
304+
end
305+
306+
test "prefix is empty" do
307+
assert List.ends_with?([1], [])
308+
assert List.ends_with?([1, 2], [])
309+
assert List.ends_with?([1, 2, 3], [])
310+
end
311+
312+
test "only accepts proper lists" do
313+
message = "no function clause matching in List.ends_with_offset/2"
314+
315+
assert_raise FunctionClauseError, message, fn ->
316+
List.ends_with?([1 | 2], [1 | 2])
317+
end
318+
319+
message = "no function clause matching in List.ends_with_offset/2"
320+
321+
assert_raise FunctionClauseError, message, fn ->
322+
List.ends_with?([1, 2], 1)
323+
end
324+
end
325+
end
326+
288327
test "to_string/1" do
289328
assert List.to_string([, ]) == "æß"
290329
assert List.to_string([?a, ?b, ?c]) == "abc"

0 commit comments

Comments
 (0)