在Erlang中列表分区和splitwith之间有什么区别吗?

时间:2016-05-04 19:43:47

标签: list data-structures functional-programming erlang

喜欢标题。 lists:partition/2lists:splitwith/2都将函数谓词和列表作为输入,并生成一个包含两个列表的元组,一个谓词返回true,另一个谓词返回false

让我困惑的是最后一句:

  

另请参阅(此处是另一个函数),以便对列表进行分区。

当然,他们会写这两个函数以相同的方式对列表进行分区,而不是以不同的方式对它们进行相同的分析?

2 个答案:

答案 0 :(得分:3)

对于你的问题 - 是的,这些功能之间存在差异。现在解释一下:

lists:splitwith/2

的文档中所述
  

根据ListPred分区为两个列表。 splitwith/2表现得很好   好像它的定义如下:

     

splitwith(Pred, List) -> {takewhile(Pred, List), dropwhile(Pred, List)}.

这意味着Pred(Elem)从第一个元素开始运行来自List的元素。 Pred(Elem)返回true时,Elem将添加到第一个列表中。 一旦,我们会找到Pred(Elem)返回false的元素,List中的其他元素将转到第二个列表。

相比之下,lists:partition/2Pred(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将结束递归。