搜索具有重复元素的记录列表
Searching through lists of records with repeating elements
我需要用 Erlang 制作一个地址簿。除了一个给我带来问题的功能外,我几乎完成了所有工作。
我的记录是:
-record(contact, {fname, lname, phone=[], mail=[], city=[], street=[]}).
我必须编写一个函数来搜索 contact
的实例并找到所有具有特定 city
名称的实例,并且对于这些实例 return {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
,搜索可以产生多个 return 值,因此它必须收集所有匹配项。
如何处理这个问题?我考虑过列表理解,例如:
{X,Y} || X<-H#contact.fname, Y<-H#contact.lname, City=:=H#contact.city
但它将 return 来自单个 ASCII 代码的元组:/
您可以使用列表理解。假设您的地址簿存储在一个名为 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.
之所以可行,是因为记录实际上是元组。用作 lists:keyfind/3
的第二个参数的构造 #contact.phone
提供基础元组的 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).
我需要用 Erlang 制作一个地址簿。除了一个给我带来问题的功能外,我几乎完成了所有工作。
我的记录是:
-record(contact, {fname, lname, phone=[], mail=[], city=[], street=[]}).
我必须编写一个函数来搜索 contact
的实例并找到所有具有特定 city
名称的实例,并且对于这些实例 return {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
,搜索可以产生多个 return 值,因此它必须收集所有匹配项。
如何处理这个问题?我考虑过列表理解,例如:
{X,Y} || X<-H#contact.fname, Y<-H#contact.lname, City=:=H#contact.city
但它将 return 来自单个 ASCII 代码的元组:/
您可以使用列表理解。假设您的地址簿存储在一个名为 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.
之所以可行,是因为记录实际上是元组。用作 lists:keyfind/3
的第二个参数的构造 #contact.phone
提供基础元组的 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).