我需要在Erlang中制作一个地址簿。我做了几乎所有的事情,除了一个给我带来问题的功能。
我的记录是:
-record(contact, {fname, lname, phone=[], mail=[], city=[], street=[]}).
我必须编写一个函数来搜索contact
的实例并查找具有特定city
名称的所有实例,并为这些实例返回{fname,lname}
元组。不同的联系人当然可以拥有相同的城市。
当我需要mail
和phone
字段的类似功能时,我就这样做了:
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).
但mail
和phone
都是唯一值,因此无论何时找到该函数,该函数都将完成。对于city
,搜索可以产生多个返回值,因此它必须收集所有匹配项。
如何处理这个问题?我认为列表理解类似于:
{X,Y} || X<-H#contact.fname, Y<-H#contact.lname, City=:=H#contact.city
但它会从单个ASCII码返回元组:/
答案 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).