File 5351-Adding-lists-uniq-1-and-lists-uniq-2.patch of Package erlang
From de65b7f94dd846fbebc3d64272495da623197bab Mon Sep 17 00:00:00 2001
From: Gian Lorenzo Meocci <glmeocci@gmail.com>
Date: Thu, 3 Mar 2022 10:31:05 +0100
Subject: [PATCH] Adding lists:uniq/1 and lists:uniq/2
---
lib/stdlib/doc/src/lists.xml | 37 +++++++++++++++++++++++++++
lib/stdlib/src/lists.erl | 45 +++++++++++++++++++++++++++++++--
lib/stdlib/test/lists_SUITE.erl | 28 +++++++++++++++++---
3 files changed, 105 insertions(+), 5 deletions(-)
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index 063c9d19a8..8b39279b48 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -1126,6 +1126,43 @@ splitwith(Pred, List) ->
[[a,x,1],[b,y,2],[c,z,3]]</pre>
</desc>
</func>
+
+ <func>
+ <name name="uniq" arity="1" since="OTP 25.0"/>
+ <fsummary>Removes duplicate elements of a list preserving the order.</fsummary>
+ <desc>
+ <p>Returns a list containing the elements of
+ <c><anno>List1</anno></c> with duplicated elements removed
+ (preserving the order of the elements). The first occurrence of
+ each element is kept.</p>
+ <p><em>Examples:</em></p>
+ <pre>
+> <input>lists:uniq(fun([3,3,1,2,1,2,3]).</input>
+[3,1,2]
+> <input>lists:uniq([a, a, 1, b, 2, a, 3]).</input>
+[a, 1, b, 2, 3]</pre>
+ </desc>
+ </func>
+
+ <func>
+ <name name="uniq" arity="2" since="OTP 25.0"/>
+ <fsummary>
+ Removes duplicate elements of a list using
+ a fun as a key preserving the order.
+ </fsummary>
+ <desc>
+ <p>Returns a list containing the elements of
+ <c><anno>List1</anno></c> without the elements for which
+ <c><anno>Fun</anno></c> returned duplicate values
+ (preserving the order of the elements). The first occurrence
+ of each element is kept.</p>
+ <p><em>Examples:</em></p>
+ <pre>
+> <input>lists:uniq(fun({X, _}) -> X end, [{b, 2}, {a, 1}, {c, 3}, {a, 2}]).</input>
+[{b, 2}, {a, 1}, {c, 3}]</pre>
+ </desc>
+ </func>
+
</funcs>
</erlref>
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index 2a9122384b..96898a88f5 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -36,7 +36,7 @@
prefix/2, reverse/1, seq/2, seq/3,
split/2, sublist/2, sublist/3,
subtract/2, suffix/2, sum/1,
- unzip/1, unzip3/1,
+ uniq/1, unzip/1, unzip3/1,
zip/2, zip3/3]).
%% Functions taking a list of tuples and a position within the tuple.
@@ -59,7 +59,7 @@
foldl/3, foldr/3, foreach/2,
map/2, mapfoldl/3, mapfoldr/3,
partition/2, search/2,
- splitwith/2, takewhile/2,
+ splitwith/2, takewhile/2, uniq/2,
zipwith/3, zipwith3/4]).
%% Undocumented, but used within Erlang/OTP.
@@ -2975,3 +2975,44 @@ rufmerge2_2(H1, T1, Fun, [], M, H2M) ->
lists:reverse(T1, [H1, H2M | M])
end.
+%% uniq/1: return a new list with the unique elements of the given list
+
+-spec uniq(List1) -> List2 when
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
+
+uniq(L) ->
+ uniq_1(L, #{}).
+
+uniq_1([X | Xs], M) ->
+ case is_map_key(X, M) of
+ true ->
+ uniq_1(Xs, M);
+ false ->
+ [X | uniq_1(Xs, M#{X => true})]
+ end;
+uniq_1([], _) ->
+ [].
+
+%% uniq/2: return a new list with the unique elements of the given list using a function key
+
+-spec uniq(Fun, List1) -> List2 when
+ Fun :: fun((T) -> any()),
+ List1 :: [T],
+ List2 :: [T],
+ T :: term().
+
+uniq(F, L) when is_function(F, 1) ->
+ uniq_2(L, F, #{}).
+
+uniq_2([X | Xs], F, M) ->
+ Key = F(X),
+ case is_map_key(Key, M) of
+ true ->
+ uniq_2(Xs, F, M);
+ false ->
+ [X | uniq_2(Xs, F, M#{Key => true})]
+ end;
+uniq_2([], _, _) ->
+ [].
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index 68fb1cd92f..26b71887fa 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -32,7 +32,7 @@
%% Test cases must be exported.
-export([member/1, reverse/1,
keymember/1, keysearch_keyfind/1,
- keystore/1, keytake/1, keyreplace/1,
+ keystore/1, keytake/1, keyreplace/1,
append_1/1, append_2/1,
seq_loop/1, seq_2/1, seq_3/1, seq_2_e/1, seq_3_e/1,
@@ -53,6 +53,7 @@
ufunmerge/1, rufunmerge/1,
ufunsort_1/1, ufunsort_stable/1, ufunsort_rand/1,
ufunsort_error/1,
+ uniq_1/1, uniq_2/1,
zip_unzip/1, zip_unzip3/1, zipwith/1, zipwith3/1,
filter_partition/1,
join/1,
@@ -81,10 +82,11 @@ suite() ->
all() ->
[{group, append},
{group, key},
- {group,sort},
+ {group, sort},
{group, usort},
{group, keysort},
{group, ukeysort},
+ {group, uniq},
{group, funsort},
{group, ufunsort},
{group, sublist},
@@ -120,6 +122,7 @@ groups() ->
[flatten_1, flatten_2, flatten_1_e, flatten_2_e]},
{tickets, [parallel], [otp_5939, otp_6023, otp_6606, otp_7230]},
{zip, [parallel], [zip_unzip, zip_unzip3, zipwith, zipwith3]},
+ {uniq, [parallel], [uniq_1, uniq_2]},
{misc, [parallel], [reverse, member, dropwhile, takewhile,
filter_partition, suffix, subtract, join,
hof, droplast, search, enumerate]}
@@ -2758,3 +2761,22 @@ enumerate(Config) when is_list(Config) ->
{'EXIT', {function_clause, _}} = catch lists:enumerate(1, <<1,2,3>>),
ok.
+
+uniq_1(_Config) ->
+ [] = lists:uniq([]),
+ [foo] = lists:uniq([foo]),
+ ["foo", "bar", "zoo"] = lists:uniq(["foo", "foo", "bar", "foo", "zoo",
+ "foo", "bar", "zoo"]),
+ [a, 1, b, 2] = lists:uniq([a, a, a, 1, b, 2, a, 2, 1]),
+ [<<"home">>, "home"] = lists:uniq([<<"home">>, "home"]),
+ [3.14159, 2.71828, 3.17] = lists:uniq([3.14159, 3.14159, 2.71828, 3.17]),
+ [42, 42.0] = lists:uniq([42, 42.0, 42, 42.0]),
+ ok.
+
+uniq_2(_Config) ->
+ [] = lists:uniq(fun(X) -> X end, []),
+ [{42, 1}, {42.0, 99}, {a, 99}] =
+ lists:uniq(fun(X) -> element(1, X) end,
+ [{42, 1}, {42.0, 99}, {a, 99}, {a, 1}, {42, 100}]),
+ [1] = lists:uniq(fun(_) -> whatever end, lists:seq(1, 10)),
+ ok.
--
2.34.1