Erlang:使用递归从列表中选择唯一项

时间:2013-03-13 17:01:01

标签: recursion erlang

给出Erlang中的任何列表,例如:

L = [foo, bar, foo, buzz, foo].

如何使用递归函数仅显示该列表的唯一项? 我不想使用内置函数,就像列表函数之一(如果存在)。

在我的例子中,我想要的是一个新列表,例如

SL = [bar, buzz].

我的猜测是,在应用过滤器之前,我会首先使用快速排序功能对列表进行排序吗?

任何建议都会有所帮助。这个例子是Cesarini& Sons第3章练习的变种。汤普森出色的“Erlang编程”一书。

9 个答案:

答案 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))。或者甚至更好,自己写一个反向功能! (这很容易)。