[erlang-questions] performing lists:keysearch on a list of records

zxq9 zxq9@REDACTED
Mon Nov 23 09:58:46 CET 2015


Hi Zhiqian,

This question just came up the other day on SO:
http://stackoverflow.com/questions/33846975/searching-through-lists-of-records-with-repeating-elements

As usual, Steve was all over it, and actually provided this exact solution.

On 2015年11月23日 月曜日 09:07:38 Sergej Jurečko wrote:
> lists:keyfind is faster and returns result directly instead of
> {value,Result}.
> 
> For records, you should use: lists:keyfind(Value,#myrecord.myelement, List).
> 
> Compiler will turn: #myrecord.myelement into a tuple position.

It seems like the "records -> goblins?" translation is being asked about a bit more than usual these days, so here is a way to check exactly what code results after precompilation by doing "erlc -E somemodule.erl".

Here is an example module (based on Steve's SO answer):


  -module(recfind).
  -export([find_by_phone/2, find_by_mail/2]).

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

  find_by_phone(Phone, AddressBook) -> find(Phone, #contact.phone, AddressBook).
  find_by_mail(Mail, AddressBook) -> find(Mail, #contact.mail, AddressBook).

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


Here is the command to produce the source file after all source translations, but before compilation:
  ceverett@REDACTED:~/Code/erlang$ erlc -E recfind.erl

And here is the resulting translated code (in a file called "recfind.E"):


  -file("recfind.erl", 1).

  find_by_phone(Phone, AddressBook) ->
      find(Phone, 4, AddressBook).

  find_by_mail(Mail, AddressBook) ->
      find(Mail, 5, AddressBook).

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

  module_info() ->
      erlang:get_module_info(recfind).

  module_info(X) ->
      erlang:get_module_info(recfind, X).


We see that `find(Mail, #contact.mail, AddressBook)`
has been translated to `find(Mail, 5, AddressBook)`.

Sometimes this is interesting to do when a lot of preprocessing magic is involved in a source file and you want to know what the effect some construct or environment settings actually has in the resulting code (did those macros really fire?). Other interesting compiler options are `-P` and `-S`. The -E, -P, and -S switches for erlc are the same as the 'E', 'P', and 'S' options for compile:file/2 (http://www.erlang.org/doc/man/compile.html#file-2).

-Craig



More information about the erlang-questions mailing list