搜索具有重复元素的记录列表

时间:2015-11-21 18:23:50

标签: erlang list-comprehension record

我需要在Erlang中制作一个地址簿。我做了几乎所有的事情,除了一个给我带来问题的功能。

我的记录是:

-record(contact, {fname, lname, phone=[], mail=[], city=[], street=[]}).

我必须编写一个函数来搜索contact的实例并查找具有特定city名称的所有实例,并为这些实例返回{fname,lname}元组。不同的联系人当然可以拥有相同的城市。

当我需要mailphone字段的类似功能时,我就这样做了:

findByPhone(_,[]) -> {error,"not found"};
findByPhone(Phone,[H|T]) ->
  case findPhoneForUser(Phone, H#contact.phone) of
    true -> {H#contact.fname, H#contact.lname};
    false -> findByPhone(Phone, T)
  end.
findPhoneForUser(_,[]) -> false;
findPhoneForUser(Phone, [Phone|_]) -> true;
findPhoneForUser(Phone, [_|T]) -> findPhoneForUser(Phone, T).

mailphone都是唯一值,因此无论何时找到该函数,该函数都将完成。对于city,搜索可以产生多个返回值,因此它必须收集所有匹配项。

如何处理这个问题?我认为列表理解类似于:

{X,Y} || X<-H#contact.fname, Y<-H#contact.lname, City=:=H#contact.city

但它会从单个ASCII码返回元组:/

1 个答案:

答案 0 :(得分:3)

您可以使用列表理解。假设您的地址簿存储在名为AddressBook的变量中,并且您匹配的城市存储在名为City的变量中,以下内容将起作用:

[{C#contact.fname, C#contact.lname} || C <- AddressBook, C#contact.city == City].

另请注意,您可以使用lists:keyfind/3 function

简化findByPhone功能
findByPhone(Phone, AddressBook) ->
    case lists:keyfind(Phone, #contact.phone, AddressBook) of
        #contact{fname=Fname, lname=Lname} -> {Fname, Lname};
        false -> {error, not_found}
    end.

这是有效的,因为记录是封面下的元组。用作#contact.phone的第二个参数的构造lists:keyfind/3提供了基础元组的phone字段的元素编号。实际上,您可以使用此方法编写一个支持记录中任何唯一字段的非导出find函数,然后为每个可搜索字段编写导出函数:

find(Value, Field, AddressBook) ->
    case lists:keyfind(Value, Field, AddressBook) of
        #contact{fname=Fname, lname=Lname} -> {Fname, Lname};
        false -> {error, not_found}
    end.

findByPhone(Phone, AddressBook) -> find(Phone, #contact.phone, AddressBook).
findByMail(Mail, AddressBook) -> find(Mail, #contact.mail, AddressBook).