Erlang Thurday – lists:delete/2

今天的Erlang Thursday讲的是 lists:delete/2

lists:delete/2 接收一个Erlang term作为它的第一个入参,它将把该term从第二个入参--一个列表里删除掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
lists:delete(1, [8, 7, 6, 5, 4, 3, 2, 1]).
% [8,7,6,5,4,3,2]
lists:delete(4, [1, 1, 2, 3, 5, 8]).
% [1,1,2,3,5,8]
lists:delete(72, "Hello World!").
% "ello World!"
lists:delete(d, [a, b, c, d]).
% [a,b,c]
lists:delete(4, []).
% []
lists:delete({b, 2}, [{a, 1}, {b, 2}, {c, 3}]).
% [{a,1},{c,3}]
lists:delete([1, 2, 3], [[4, 5, 6], [7, 8, 9], [1, 2, 3]]).
% [[4,5,6],[7,8,9]]

注意:lists:delete/2 仅仅是将第一个在列表里发现的term删掉,而其他任何在列表里同样的term它不会删除。

1
2
€lists:delete(1, [1, 1, 2, 3, 5, 8]).
% [1,2,3,5,8]

因为 lists:delete/2 是一个非常简单就能讲清楚用法的函数,这样这篇文章将可能非常短,所以我想在下面我们展示一下如何自己来写一个非常简单(1) 的 lists:delete/2 实现是非常值得的。

1
2
3
4
5
6
7
8
9
10
11
12
13
-module(my_lists).
-export([delete/2]).
delete(Item, List) ->
delete(Item, [], List).
delete(Item, Checked, [Item|Rest]) ->
lists:reverse(Checked) ++ Rest;
delete(Item, Checked, [Head|Rest]) ->
delete(Item, [Head | Checked], Rest);
delete(_Item, Checked, []) ->
lists:reverse(Checked).

让我们一起看看我们的delete函数在被调用的时候是如何执行的?

my_lists:delete/2 是一个友好的API函数,它仅仅是调用一个“私有”函数(没有导出的函数)-- delete/3,所以调用者不需要担心那个我们传递的已经检查了的一个空列表作为初始值的累加器。

1
2
3
4
5
6
-module(my_lists).
-export([delete/2]).
delete(Item, List) ->
delete(Item, [], List).

delete/3函数的第一个分支用模式匹配来检查我们想要删除掉元素是否也是需要检查的列表的第一个元素。如果模式匹配成果,我们会看到第一个元素被删除!接着我们就能停止处理列表并返回的结果,而这个结果是由我们已经检查过的元素组成列表的反转列表和那些剩下的我们还没有检查的元素组成的列表一起构成的。

1
2
delete(Item, Checked, [Item|Rest]) ->
lists:reverse(Checked) ++ Rest;

第二个分支“知道”我们想删除掉元素和剩下的列表的第一个元素不匹配。它是怎么“知道”的?因为如果它们匹配,第一个分支将模式匹配成功而第二个分支将得不到执行的机会。因为我们找不到元素需要被删除,我们通过将元素加到被检查过的元素组成的列表头部,并且继续调用 delete/3 。我们通过在被检查过的元素组成的列表头部加上元素形成新的被检查过元素组成的列表的做法就是为什么我们在第一分支和第三分支需要反转被检查元素组成的列表的原因。

1
2
delete(Item, Checked, [Head|Rest]) ->
delete(Item, [Head | Checked], Rest);

第三个也是最后一个 delete/3 函数的分支已经搜索到列表的结尾并且没有发现相同的元素,所以我们只是将被检查过的元素组成的列表反转后返回。

1
2
delete(_Item, Checked, []) ->
lists:reverse(Checked).

这就是你自己的简单(1)版 lists:delete/2 的实现。

1、简单的意思是因为这个版本没有进行性能优化,或者没有做彻底的是否完全符合 lists:delete/2 规范的测试。

原文链接: https://www.proctor-it.com/erlang-thurday-lists-delete-2/