From 7b622bbcae9d2a1d2d1120e2e308aad1e26c4b8d Mon Sep 17 00:00:00 2001 From: Paul Guyot Date: Sun, 22 Sep 2024 16:05:46 +0200 Subject: [PATCH] Add `lists:last/1` and `lists:mapfoldl/3` Signed-off-by: Paul Guyot --- libs/estdlib/src/lists.erl | 30 ++++++++++++++++++++++++++++++ tests/libs/estdlib/test_lists.erl | 15 +++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/libs/estdlib/src/lists.erl b/libs/estdlib/src/lists.erl index fb9e8ad80c..b6656a729b 100644 --- a/libs/estdlib/src/lists.erl +++ b/libs/estdlib/src/lists.erl @@ -32,6 +32,7 @@ -export([ map/2, nth/2, + last/1, member/2, delete/2, reverse/1, @@ -45,6 +46,7 @@ keytake/3, foldl/3, foldr/3, + mapfoldl/3, all/2, any/2, flatten/1, @@ -90,6 +92,16 @@ nth(1, [H | _T]) -> nth(Index, [_H | T]) when Index > 1 -> nth(Index - 1, T). +%%----------------------------------------------------------------------------- +%% @param L the proper list from which to get the last item +%% @returns the last item of the list. +%% @doc Get the last item of a list. +%% @end +%%----------------------------------------------------------------------------- +-spec last(L :: nonempty_list(E)) -> E. +last([E]) -> E; +last([_H | T]) -> last(T). + %%----------------------------------------------------------------------------- %% @param E the member to search for %% @param L the list from which to get the value @@ -372,6 +384,24 @@ foldl(Fun, Acc0, [H | T]) -> Acc1 = Fun(H, Acc0), foldl(Fun, Acc1, T). +%%----------------------------------------------------------------------------- +%% @param Fun the function to apply +%% @param Acc0 the initial accumulator +%% @param List the list over which to fold +%% @returns the result of mapping and folding Fun over L +%% @doc Combine `map/2` and `foldl/3` in one pass. +%% @end +%%----------------------------------------------------------------------------- +-spec mapfoldl(fun((A, Acc) -> {B, Acc}), Acc, [A]) -> {[B], Acc}. +mapfoldl(Fun, Acc0, List1) -> + mapfoldl0(Fun, {[], Acc0}, List1). + +mapfoldl0(_Fun, {List1, Acc0}, []) -> + {?MODULE:reverse(List1), Acc0}; +mapfoldl0(Fun, {List1, Acc0}, [H | T]) -> + {B, Acc1} = Fun(H, Acc0), + mapfoldl0(Fun, {[B | List1], Acc1}, T). + %%----------------------------------------------------------------------------- %% @equiv foldl(Fun, Acc0, reverse(List)) %% @doc Fold over a list of terms, from right to left, applying Fun(E, Accum) diff --git a/tests/libs/estdlib/test_lists.erl b/tests/libs/estdlib/test_lists.erl index bb7350e65b..133a33f2c0 100644 --- a/tests/libs/estdlib/test_lists.erl +++ b/tests/libs/estdlib/test_lists.erl @@ -46,6 +46,8 @@ test() -> ok = test_split(), ok = test_usort(), ok = test_filtermap(), + ok = test_last(), + ok = test_mapfoldl(), ok. test_nth() -> @@ -296,4 +298,17 @@ test_filtermap() -> ), ok. +test_last() -> + ?ASSERT_ERROR(lists:last([]), function_clause), + ?ASSERT_MATCH(a, lists:last([a])), + ?ASSERT_MATCH(b, lists:last([a, b])), + ?ASSERT_ERROR(lists:last([a | b]), function_clause), + ok. + +test_mapfoldl() -> + ?ASSERT_MATCH({[], 1}, lists:mapfoldl(fun(X, A) -> {X * A, A + 1} end, 1, [])), + ?ASSERT_MATCH({[1, 4, 9], 4}, lists:mapfoldl(fun(X, A) -> {X * A, A + 1} end, 1, [1, 2, 3])), + ?ASSERT_ERROR(lists:mapfoldl(fun(X, A) -> {X * A, A + 1} end, 1, foo), function_clause), + ok. + id(X) -> X.