【问题标题】:Searching through lists of records with repeating elements搜索具有重复元素的记录列表
【发布时间】:2015-11-21 18:23:50
【问题描述】:

我需要在 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 码返回元组:/

【问题讨论】:

    标签: erlang list-comprehension record


    【解决方案1】:

    您可以使用列表推导。假设您的通讯录存储在名为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).
    

    【讨论】:

    • 我按照你的方式做了,但它返回空列表[]。我调用函数findByCity(City, AB),其中City 是城市字符串,AB 是存储填充记录的地址簿。我在列表 compr 中更改了 AB 上的地址簿。当然。
    • pastebin.com/3W04T40m 这就是函数的样子。它不会返回空列表而是错误,因为List 是空的。
    • 感谢您的示例,但您还需要显示 CityAB 变量的值,然后才能帮助您。在此之前,请在 Erlang shell 中尝试此操作:City = "Stockholm", [{C#contact.fname, C#contact.lname} || C &lt;- [#contact{fname="Joe", lname="Armstrong", city="Stockholm"}], C#contact.city == City].,您会看到返回的列表不为空,因为 city 符合预期。
    • 这是我的测试代码:pastebin.com/k97iev0u。我排除了所有不必要的功能并包括了一些简单的测试。列表是否为空或不为空无关紧要,它会返回类似于空列表的错误消息。那里有什么问题?您的 shell 示例有效,所以我想知道为什么它在我的地址簿中不起作用。
    • 在您的代码中,您通过H#contact{city=[City]} 将城市添加到记录中。我认为您不希望将城市列在列表中。如果您像这样设置它,它将起作用:H#contact{city=City}。我修改了你所有的代码来解决这个问题和其他问题,并使用常见的 Erlang 编码风格here,希望对您有所帮助。
    猜你喜欢
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 2023-03-14
    • 2021-09-03
    • 1970-01-01
    • 2021-06-25
    • 1970-01-01
    相关资源
    最近更新 更多