Recursion 使用递归从列表中选择唯一项
作为对昨天问题的后续行动 在Erlang中,假设我想从给定列表中选择所有唯一的项,例如Recursion 使用递归从列表中选择唯一项,recursion,erlang,Recursion,Erlang,作为对昨天问题的后续行动 在Erlang中,假设我想从给定列表中选择所有唯一的项,例如 List = [foo, bar, buzz, foo]. 我用了你的结果 NewList = [bar, buzz]. 如何在Erlang中进一步操作NewList 例如,假设我不仅要从列表中选择所有唯一的项,还要计算NewList中所有结果项的字符总数?您可以使用折叠在结果列表上递归。为了简单起见,我将您的原子转换为字符串,您可以使用list_to_atom/1执行此操作: 1> NewList
List = [foo, bar, buzz, foo].
我用了你的结果
NewList = [bar, buzz].
如何在Erlang中进一步操作NewList
例如,假设我不仅要从列表中选择所有唯一的项,还要计算NewList中所有结果项的字符总数?您可以使用折叠在结果列表上递归。为了简单起见,我将您的原子转换为字符串,您可以使用list_to_atom/1执行此操作:
1> NewList = ["bar", "buzz"].
["bar","buzz"]
2> L = lists:foldl(fun (W, Acc) -> [{W, length(W)}|Acc] end, [], NewList).
[{"buzz",4},{"bar",3}]
这将返回一个可访问的proplist,如下所示:
3> proplists:get_value("buzz", L).
4
如果您想自己构建递归以达到教学目的,而不是使用列表:
count_char_in_list([], Count) ->
Count;
count_char_in_list([Head | Tail], Count) ->
count_char_in_list(Tail, Count + length(Head)). % a string is just a list of numbers
然后:
1> test:count_char_in_list(["bar", "buzz"], 0).
7
在函数式编程中,我们有频繁出现的模式,它们应该有自己的名称和支持函数。两个最广泛使用的是地图和折叠有时减少。这两个函数构成了列表操作的基本构造块,通常无需编写专用的递归函数 地图 map函数按顺序迭代列表,生成一个新列表,其中每个元素都是将函数应用于原始列表中相应元素的结果。以下是典型地图的实现方式:
map(Fun, [H|T]) -> % recursive case
[Fun(H)|map(Fun, T)];
map(_Fun, []) -> % base case
[].
这是递归函数的完美入门示例;粗略地说,函数子句要么是递归情况,导致使用较小的问题实例调用iself,要么是基本情况,不进行递归调用
那个么你们如何使用地图呢?请注意,第一个参数Fun应该是一个函数。在Erlang中,可以声明有时称为lambdas inline的匿名函数。例如,要将列表中的每个数字平方,请生成一个平方列表:
map(fun(X) -> X*X end, [1,2,3]). % => [1,4,9]
这是一个例子
注意,map是Erlang标准库的一部分,如list:map/2
折叠
map在一个列表和另一个列表之间创建1:1的元素映射,而fold的目的是对列表中的每个元素应用一些函数,同时累积单个结果,例如sum。正确的折叠有助于将其视为向右折叠,可能看起来是这样的:
foldr(Fun, Acc, [H|T]) -> % recursive case
foldr(Fun, Fun(H, Acc), T);
foldr(_Fun, Acc, []) -> % base case
Acc.
使用此函数,我们可以对列表中的元素求和:
foldr(fun(X, Sum) -> Sum + X, 0, [1,2,3,4,5]). %% => 15
请注意,foldr和foldl都是列表模块中Erlang标准库的一部分
虽然这可能不是很明显,但一大类常见的列表操作问题可以单独使用map和fold来解决
递归思考
编写递归算法一开始可能会让人望而生畏,但当您习惯了它之后,它就变得非常自然了。遇到问题时,您应该确定两件事:
如何将问题分解为更小的实例?为了使递归有用,递归调用必须以较小的问题作为参数,否则函数永远不会终止。
基本情况是什么,即终止标准?
关于1,考虑计数列表元素的问题。这怎么可能分解成更小的子问题呢?好吧,这样想:给定一个非空列表,其第一个元素头是X,其余元素尾是Y,其长度为1+Y的长度。由于Y小于列表[X | Y],我们成功地减少了问题
继续列表示例,我们什么时候停止?嗯,最终,尾巴将是空的。我们回到基本情况,即空列表的长度为零的定义。您会发现,为各种情况编写函数子句非常类似于为字典编写定义:%% Definition:
%% The length of a list whose head is H and whose tail is T is
%% 1 + the length of T.
length([H|T]) ->
1 + length(T);
%% Definition: The length of the empty list ([]) is zero.
length([]) ->
0.
谢谢你迄今为止的回答。但是,我不想再次手动输入列表,也就是说,我对次要的字符计数功能不太感兴趣,而是更关心如何将使原始列表唯一的结果“延续”到自动使用结果进行进一步操作,无论是计数字符还是其他操作。谢谢,NewList是一个变量,使用它就行了。你能详细说明一下吗?当然可以。假设我的列表是list=[foo,bar,buzz,foo]。我想要所有独特物品的总字符数。进一步假设我使用了uniquesL->uniquesL,[],[]代码。uniques[],ux,Acc->list:reverseAcc;uniques[X | Rest],Seen,Acc->case list:memberX,Seen of true->uniquesRest,Seen,list:deleteX,Acc;false->uniquesRest,[X|Seen],[X|Acc]结束。代码,以便获得唯一的项目。我需要如何修改代码smippet以获得字符数,就像一个例子一样?uniques_and_charsL->uniques=uniquesL,num_charsUniques。请注意,您正在使用fold重新创建映射,因为您正在使用1:1元素映射创建一个列表。非常好的解释。非常感谢你。正是我所需要的。试图将你的指导应用到一个具体的例子中,但仍然有点不确定:假设我的列表是list=[a,b,c,a]。我需要总的n o。仅限所有唯一项的字符。进一步假设我现在使用了uniquesL->uniquesL,[],[]。uniques[],ux,Acc->list:reverseAcc;uniques[X | Rest],Seen,Acc->case list:memberX,Seen of true->uniquesRest,Seen,list:deleteX,Acc;false->uniquesRest,[X|Seen],[X|Acc]结束。以获取唯一的项目。作为一个例子,我将如何更改此代码smippet以同时获取字符数?很多很多,uniques的输出是另一个列表,对吗?将该列表作为输入传递给下面的William Cummings:在列表中组合函数可能非常强大。您可以将其视为从一个Unix命令到另一个Unix命令的管道输出。