给出Erlang中的任何列表,例如:
L = [foo, bar, foo, buzz, foo].
如何使用递归函数仅显示该列表的唯一项? 我不想使用内置函数,就像列表函数之一(如果存在)。
在我的例子中,我想要的是一个新列表,例如
SL = [bar, buzz].
我的猜测是,在应用过滤器之前,我会首先使用快速排序功能对列表进行排序吗?
任何建议都会有所帮助。这个例子是Cesarini& Sons第3章练习的变种。汤普森出色的“Erlang编程”一书。
答案 0 :(得分:7)
我建议这个:
unique(L) ->
unique([],L).
unique(R,[]) -> R;
unique(R,[H|T]) ->
case member_remove(H,T,[],true) of
{false,Nt} -> unique(R,Nt);
{true,Nt} -> unique([H|R],Nt)
end.
member_remove(_,[],Res,Bool) -> {Bool,Res};
member_remove(H,[H|T],Res,_) -> member_remove(H,T,Res,false);
member_remove(H,[V|T],Res,Bool) -> member_remove(H,T,[V|Res],Bool).
member_remove函数在一次传递中返回剩余的尾部,而不会检查所有出现的元素是否重复以及测试结果。
答案 1 :(得分:3)
我可以这样做:)
get_unique(L) ->
SortedL = lists:sort(L),
get_unique(SortedL, []).
get_unique([H | T], [H | Acc]) ->
get_unique(T, [{dup, H} | Acc]);
get_unique([H | T], [{dup, H} | Acc]) ->
get_unique(T, [{dup, H} | Acc]);
get_unique([H | T], [{dup, _} | Acc]) ->
get_unique(T, [H | Acc]);
get_unique([H | T], Acc) ->
get_unique(T, [H | Acc]);
get_unique([], [{dup, _} | Acc]) ->
Acc;
get_unique([], Acc) ->
Acc.
答案 2 :(得分:1)
使用两个累加器。一个用来保存你到目前为止看到的元素,一个用于保存实际结果。如果您是第一次看到该项目(不在“看见”列表中),请将该项目添加到两个列表中并递归。如果您之前已经看过该项目,请在递归之前将其从结果列表(Acc)中删除。
-module(test).
-export([uniques/1]).
uniques(L) ->
uniques(L, [], []).
uniques([], _, Acc) ->
lists:reverse(Acc);
uniques([X | Rest], Seen, Acc) ->
case lists:member(X, Seen) of
true -> uniques(Rest, Seen, lists:delete(X, Acc));
false -> uniques(Rest, [X | Seen], [X | Acc])
end.
答案 3 :(得分:1)
我认为想法可能是:检查你是否已经看过列表的负责人。如果是这样,跳过它并递归检查尾部。如果不是 - 将当前头部添加到结果,“看到”并递归检查尾部。用于检查您是否已经看过该项目的最合适的结构已设置。
所以,我建议遵循:
remove_duplicates(L) -> remove_duplicates(L,[], sets:new()).
remove_duplicates([],Result,_) -> Result;
remove_duplicates([Head|Tail],Result, Seen) ->
case sets:is_element(Head,Seen) of
true -> remove_duplicates(Tail,Result,Seen);
false -> remove_duplicates(Tail,[Head|Result], sets:add_element(Head,Seen))
end.
答案 4 :(得分:0)
此解决方案仅过滤掉列表中的重复项。可能需要建立在它做你想做的事情上。
remove_duplicates(List)-> lists:reverse(removing(List,[])). removing([],This) -> This; removing([A|Tail],Acc) -> removing(delete_all(A,Tail),[A|Acc]). delete_all(Item, [Item | Rest_of_list]) -> delete_all(Item, Rest_of_list); delete_all(Item, [Another_item| Rest_of_list]) -> [Another_item | delete_all(Item, Rest_of_list)]; delete_all(_, []) -> [].
编辑
Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\Windows\System32>erl Eshell V5.9 (abort with ^G) 1> List = [1,2,3,4,a,b,e,r,a,b,v,3,2,1,g,{red,green},d,2,5,6,1,4,6,5,{red,green}]. [1,2,3,4,a,b,e,r,a,b,v,3,2,1,g, {red,green}, d,2,5,6,1,4,6,5, {red,green}] 2> remove_duplicates(List). [1,2,3,4,a,b,e,r,v,g,{red,green},d,5,6] 3>
答案 5 :(得分:0)
尝试以下代码
-module(util).
-export([unique_list/1]).
unique_list([]) -> [];
unique_list(L) -> unique_list(L, []).
% Base Case
unique_list([], Acc) ->
lists:reverse(Acc);
% Recursive Part
unique_list([H|T], Acc) ->
case lists:any(fun(X) -> X == H end, T) of
true ->
unique_list(lists:delete(H,T), Acc);
false ->
unique_list(T, [H|Acc])
end.
答案 6 :(得分:0)
唯一(L) - >集:to_list(套:from_list(L))。
答案 7 :(得分:0)
unique(List) ->
Set = sets:from_list(List),
sets:to_list(Set).
答案 8 :(得分:-1)
最简单的方法是使用带有“累加器”的函数来跟踪您已经拥有的元素。 所以你要写一个像
这样的函数%unique_acc(Accumulator,List_to_take_from)。
通过不导出累加器版本,而不是导出其调用者,您仍然可以拥有一个干净的功能:
-module(uniqueness).
-export([unique/1]).
unique(List) ->
unique_acc([], List).
如果要取的列表为空,则表示您已完成:
unique_acc(Accumulator, []) ->
Accumulator;
如果不是:
unique_acc(Accumulator, [X|Xs]) ->
case lists:member(X, Accumulator) of
true -> unique_acc(Accumulator, Xs);
false -> unique_acc([X|Accumulator], Xs)
end.
有两点需要注意:
- 此 使用列表BIF - lists:member/2
。不过,你可以轻松地写出来
- 从原始列表到结果,元素的顺序颠倒过来。如果您不喜欢这样,可以将unique/1
定义为lists:reverse(unique_acc([], List))
。或者甚至更好,自己写一个反向功能! (这很容易)。