Skip to content

Commit 318ca03

Browse files
committed
Add List.ends_with?/2
1 parent cc70737 commit 318ca03

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
@@ -924,6 +924,44 @@ defmodule List do
924924
def starts_with?(list, []) when is_list(list), do: true
925925
def starts_with?(list, [_ | _]) when is_list(list), do: false
926926

927+
@doc """
928+
Returns `true` if `list` ends with the given `suffix` list, otherwise returns `false`.
929+
930+
If `suffix` is an empty list, it returns `true`.
931+
932+
### Examples
933+
934+
iex> List.ends_with?([1, 2, 3], [2, 3])
935+
true
936+
937+
iex> List.ends_with?([1, 2], [1, 2, 3])
938+
false
939+
940+
iex> List.ends_with?([:alpha], [])
941+
true
942+
943+
iex> List.ends_with?([], [:alpha])
944+
false
945+
946+
"""
947+
@doc since: "1.18.0"
948+
@spec ends_with?(nonempty_list, nonempty_list) :: boolean
949+
@spec ends_with?(list, []) :: true
950+
@spec ends_with?([], nonempty_list) :: false
951+
def ends_with?(list, suffix) do
952+
case ends_with_offset(list, suffix) do
953+
nil -> false
954+
n -> :lists.nthtail(n, list) === suffix
955+
end
956+
end
957+
958+
defp ends_with_offset([], [_ | _]), do: nil
959+
defp ends_with_offset(rest, []), do: length(rest)
960+
961+
defp ends_with_offset([_ | tail], [_ | suffix_tail]) do
962+
ends_with_offset(tail, suffix_tail)
963+
end
964+
927965
@doc """
928966
Converts a charlist to an atom.
929967

lib/elixir/test/elixir/list_test.exs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,45 @@ defmodule ListTest do
292292
end
293293
end
294294

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

0 commit comments

Comments
 (0)