喜欢标题。 lists:partition/2
和lists:splitwith/2
都将函数谓词和列表作为输入,并生成一个包含两个列表的元组,一个谓词返回true
,另一个谓词返回false
。
让我困惑的是最后一句:
另请参阅(此处是另一个函数),以便对列表进行分区。
当然,他们会写这两个函数以相同的方式对列表进行分区,而不是以不同的方式对它们进行相同的分析?
答案 0 :(得分:3)
对于你的问题 - 是的,这些功能之间存在差异。现在解释一下:
如lists:splitwith/2
根据
List
将Pred
分区为两个列表。splitwith/2
表现得很好 好像它的定义如下:
splitwith(Pred, List) -> {takewhile(Pred, List), dropwhile(Pred, List)}.
这意味着Pred(Elem)
从第一个元素开始运行来自List
的元素。 Pred(Elem)
返回true
时,Elem
将添加到第一个列表中。 一旦,我们会找到Pred(Elem)
返回false
的元素,List
中的其他元素将转到第二个列表。
相比之下,lists:partition/2
在Pred(Elem)
的所有元素上运行List
。如果它返回特定元素的true
,它将转到第一个列表,如果它返回false
,该元素将转到第二个列表。它不会在返回false
的第一个元素上“停止”,例如在lists:splitwith/2
中。
让我们看一下另一个简单的例子,而不是文档中给出的两个例子:
1> List = [a,b,a,b].
[a,b,a,b]
2> Pred = fun(Elem) -> Elem =:= a end.
#Fun<erl_eval.6.54118792>
3> lists:partition(Pred,List).
{[a,a],[b,b]}
4> lists:splitwith(Pred,List).
{[a],[b,a,b]}
我们可以看到,Pred
函数在true
时返回Elem =:= a
。
如果我们运行lists:partition/2
,它将会超过所有元素。因此,我们在返回的元组的第一个列表中获取List
中等于a
的所有元素,其余元素在第二个列表中。
如果我们运行lists:splitwith/2
,迭代会在到达Pred(Elem)
返回false
的第一个元素时“停止”。在这种情况下,它在第二个元素b
上停止,并且从这个元素到列表末尾的所有元素都转到返回元组的第二个列表。
答案 1 :(得分:3)
我认为源代码非常清晰。
partition(Pred, L) ->
partition(Pred, L, [], []).
partition(Pred, [H | T], As, Bs) ->
case Pred(H) of
true -> partition(Pred, T, [H | As], Bs);
false -> partition(Pred, T, As, [H | Bs])
end;
partition(Pred, [], As, Bs) when is_function(Pred, 1) ->
{reverse(As), reverse(Bs)}.
splitwith / 2:
splitwith(Pred, List) when is_function(Pred, 1) ->
splitwith(Pred, List, []).
splitwith(Pred, [Hd|Tail], Taken) ->
case Pred(Hd) of
true -> splitwith(Pred, Tail, [Hd|Taken]);
false -> {reverse(Taken), [Hd|Tail]}
end;
splitwith(Pred, [], Taken) when is_function(Pred, 1) ->
{reverse(Taken),[]}.
当splitwith/2
为false时,您可以看到Pred
将结束递归。