<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40"><head><meta http-equiv=Content-Type content="text/html; charset=us-ascii"><meta name=Generator content="Microsoft Word 15 (filtered medium)"><style><!--
/* Font Definitions */
@font-face
{font-family:"Cambria Math";
panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
{font-family:Consolas;
panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
{mso-style-priority:99;
color:#0563C1;
text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-priority:99;
color:#954F72;
text-decoration:underline;}
p.MsoPlainText, li.MsoPlainText, div.MsoPlainText
{mso-style-priority:99;
mso-style-link:"Plain Text Char";
margin:0in;
margin-bottom:.0001pt;
font-size:11.0pt;
font-family:"Calibri","sans-serif";}
span.PlainTextChar
{mso-style-name:"Plain Text Char";
mso-style-priority:99;
mso-style-link:"Plain Text";
font-family:"Calibri","sans-serif";}
.MsoChpDefault
{mso-style-type:export-only;
font-family:"Calibri","sans-serif";}
@page WordSection1
{size:8.5in 11.0in;
margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
{page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]--></head><body lang=EN-US link="#0563C1" vlink="#954F72"><div class=WordSection1><p class=MsoPlainText>Well, using this function I write instead of ‘lists:flatten/1’ your algorithm takes 50XX instead of 62XX milliseconds when using ‘lists:flatten/1’.<o:p></o:p></p><p class=MsoPlainText>But if instead of adding the “,” in your iolist generator algorithm we do it here somehow it takes about 42XX milliseconds, I did but I still missing one comma. I get something like this "users.*,name,roles.id,roles.levelusers.name AS alias, comma missing between role.level and user.name. I think we have no control of that in ‘<span style='font-size:10.0pt;font-family:Consolas'>concat_io_list/2’</span> function.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'>concat_io_list([], Acc) -><o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'> Acc;<o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'>concat_io_list([[L | _] = List | Rest], Acc) when is_list(L)-><o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'> concat_io_list(Rest, Acc ++ join_simple_list(List, []));<o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'>concat_io_list([List | Rest], Acc) -><o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'> concat_io_list(Rest, Acc ++ List).<o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'><o:p> </o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'>join_simple_list([], Acc) -><o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'> Acc;<o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'>join_simple_list([[X | _] = Str | Xs], Acc) when is_number(X) -><o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'> join_simple_list(Xs, Acc ++ Str);<o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'>join_simple_list([Str | Xs], Acc) -><o:p></o:p></span></p><p class=MsoPlainText><span style='font-size:10.0pt;font-family:Consolas'> join_simple_list(Xs, Acc ++ join_simple_list(Str, [])).<o:p></o:p></span></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>Well thanks for all,<o:p></o:p></p><p class=MsoPlainText>Best regards,<o:p></o:p></p><p class=MsoPlainText>Ivan (son of Gilberio).<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>-----Original Message-----<br>From: Richard A. O'Keefe [mailto:ok@cs.otago.ac.nz] <br>Sent: Thursday, October 8, 2015 10:17 PM<br>To: Ivan Carmenates Garcia<br>Cc: Erlang Questions Mailing List<br>Subject: Re: [erlang-questions] Coming Back (maybe improving lists:reverse/1)</p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>On 8/10/2015, at 1:20 pm, Ivan Carmenates Garcia <<a href="mailto:co7eb@frcuba.co.cu"><span style='color:windowtext;text-decoration:none'>co7eb@frcuba.co.cu</span></a>> wrote:<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>> For example this is one of the algorithms, I optimize it as well as I could:<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>Start by optimising the documentation.<o:p></o:p></p><p class=MsoPlainText>> <o:p></o:p></p><p class=MsoPlainText>> Considering here that the order of the fields is very important!.<o:p></o:p></p><p class=MsoPlainText>> <o:p></o:p></p><p class=MsoPlainText>> %% -------------------------------------------------------------------<o:p></o:p></p><p class=MsoPlainText>> %% @private<o:p></o:p></p><p class=MsoPlainText>> %% @doc<o:p></o:p></p><p class=MsoPlainText>> %% Parses the specified list of full fields into a string containing <o:p></o:p></p><p class=MsoPlainText>> %% all full fields separated my comma.<o:p></o:p></p><p class=MsoPlainText>> %% example:<o:p></o:p></p><p class=MsoPlainText>> %% <pre><o:p></o:p></p><p class=MsoPlainText>> %% parse_full_fields([{users, '*'}, name, {roles, [id, level]},<o:p></o:p></p><p class=MsoPlainText>> %% {users, name, alias}], fun get_postgres_operator/2) -><o:p></o:p></p><p class=MsoPlainText>> %% {"users.'*',name,roles.id,roles.level,users.name AS alias",<o:p></o:p></p><p class=MsoPlainText>> %% [users, roles]}.<o:p></o:p></p><p class=MsoPlainText>> %% </pre><o:p></o:p></p><p class=MsoPlainText>> %% Returns `{[], []}' if called with `[]'.<o:p></o:p></p><p class=MsoPlainText>> %% @throws {error, invalid_return_fields_spec, InvalidForm :: any()} <o:p></o:p></p><p class=MsoPlainText>> %% @end %% <o:p></o:p></p><p class=MsoPlainText>> -------------------------------------------------------------------<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>Parsing turns a string into structure.<o:p></o:p></p><p class=MsoPlainText>Turning structure into a string is the OPPOSITE of parsing.<o:p></o:p></p><p class=MsoPlainText>You are not parsing but UNparsing.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>> -spec parse_return_full_fields(FullFieldsSpecs, Separator, OperatorFinder) -> Str when<o:p></o:p></p><p class=MsoPlainText>> FullFieldsSpecs :: proplists:proplist(),<o:p></o:p></p><p class=MsoPlainText>> Separator :: string(),<o:p></o:p></p><p class=MsoPlainText>> OperatorFinder :: fun(),<o:p></o:p></p><p class=MsoPlainText>> Str :: string().<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>This is seriously confusing.<o:p></o:p></p><p class=MsoPlainText>The thing about a proplist, as we've recently discussed in this list, is that it contains<o:p></o:p></p><p class=MsoPlainText> - atoms, where 'x' is equivalent to {'x',true}<o:p></o:p></p><p class=MsoPlainText> - pairs {Key, Value}<o:p></o:p></p><p class=MsoPlainText> - junk, which is completely ignored.<o:p></o:p></p><p class=MsoPlainText>While I don't fully understand your example, it's clear<o:p></o:p></p><p class=MsoPlainText>that name is NOT equivalent to {name,true} and<o:p></o:p></p><p class=MsoPlainText>that {users, name, alias} is NOT ignored as junk.<o:p></o:p></p><p class=MsoPlainText>So whatever you have, it certainly isn't a proplist.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>Finally, your -spec describes a function with three arguments, but the example in your comment has only two arguments.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>It looks like you are mapping<o:p></o:p></p><p class=MsoPlainText> 'atom' -> "atom"<o:p></o:p></p><p class=MsoPlainText> {'table', 'field'} -> "table.field"<o:p></o:p></p><p class=MsoPlainText> {'table', ['f1',...,'fn']} -> "table.f1" ... "table.fn"<o:p></o:p></p><p class=MsoPlainText> {'table', 'field', 'alias'} -> "table.field AS alias"<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>It would seem more logical to have<o:p></o:p></p><p class=MsoPlainText> field() = atom() | {atom(),atom()}. % {name,alias}<o:p></o:p></p><p class=MsoPlainText> fields() = field() | list(field()).<o:p></o:p></p><p class=MsoPlainText> slot() = atom() | {atom(),fields()}. % {table,fields} so that it's obvious how to put an alias inside a list of fields.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>-module(goo).<o:p></o:p></p><p class=MsoPlainText>-export([<o:p></o:p></p><p class=MsoPlainText> tables/1,<o:p></o:p></p><p class=MsoPlainText> unparse_return_full_fields/1,<o:p></o:p></p><p class=MsoPlainText> unparse_slots/1<o:p></o:p></p><p class=MsoPlainText> ]).<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>unparse_return_full_fields(Slots) -><o:p></o:p></p><p class=MsoPlainText> {lists:flatten(unparse_slots(Slots)), tables(Slots)}.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>tables([{Table,_}|Slots]) -><o:p></o:p></p><p class=MsoPlainText> Tables = tables(Slots),<o:p></o:p></p><p class=MsoPlainText> case lists:member(Table, Tables)<o:p></o:p></p><p class=MsoPlainText> of true -> Tables<o:p></o:p></p><p class=MsoPlainText> ; false -> [Table|Tables]<o:p></o:p></p><p class=MsoPlainText> end;<o:p></o:p></p><p class=MsoPlainText>tables([Name|Slots])<o:p></o:p></p><p class=MsoPlainText> when is_atom(Name) -><o:p></o:p></p><p class=MsoPlainText> tables(Slots);<o:p></o:p></p><p class=MsoPlainText>tables([]) -><o:p></o:p></p><p class=MsoPlainText> [].<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>unparse_slots([Slot|Slots]) -><o:p></o:p></p><p class=MsoPlainText> [ unparse_slot(Slot)<o:p></o:p></p><p class=MsoPlainText> | unparse_remaining_slots(Slots) ].<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>unparse_remaining_slots([]) -> <o:p></o:p></p><p class=MsoPlainText> "";<o:p></o:p></p><p class=MsoPlainText>unparse_remaining_slots(Slots) -><o:p></o:p></p><p class=MsoPlainText> ["," | unparse_slots(Slots)].<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>unparse_slot({Table,Fields}) -><o:p></o:p></p><p class=MsoPlainText> unparse_fields(Fields, atom_to_list(Table));<o:p></o:p></p><p class=MsoPlainText>unparse_slot(Name)<o:p></o:p></p><p class=MsoPlainText> when is_atom(Name) -><o:p></o:p></p><p class=MsoPlainText> atom_to_list(Name).<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>unparse_fields([Field|Fields], Table) -><o:p></o:p></p><p class=MsoPlainText> [ unparse_fields(Field, Table)<o:p></o:p></p><p class=MsoPlainText> | unparse_remaining_fields(Fields, Table) ]; unparse_fields({Name,Alias}, Table) -><o:p></o:p></p><p class=MsoPlainText> [Table, ".", atom_to_list(Name), " AS ", atom_to_list(Alias)]; unparse_fields(Name, Table)<o:p></o:p></p><p class=MsoPlainText> when is_atom(Name) -><o:p></o:p></p><p class=MsoPlainText> [Table, ".", atom_to_list(Name)].<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>unparse_remaining_fields([], _) -><o:p></o:p></p><p class=MsoPlainText> "";<o:p></o:p></p><p class=MsoPlainText>unparse_remaining_fields(Fields, Table) -><o:p></o:p></p><p class=MsoPlainText> ["," | unparse_fields(Fields, Table)].<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>With that definition, we get<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>1> c(goo).<o:p></o:p></p><p class=MsoPlainText>2> goo:unparse_slots([{users, '*'}, name, {roles, [id, level]},<o:p></o:p></p><p class=MsoPlainText> {users, {name, alias}}]). %% Note difference here.[["users",".","*"],<o:p></o:p></p><p class=MsoPlainText> ",","name",",",<o:p></o:p></p><p class=MsoPlainText> [["roles",".","id"],",",["roles",".","level"]],<o:p></o:p></p><p class=MsoPlainText> ",",<o:p></o:p></p><p class=MsoPlainText> ["users",".","name"," AS ","alias"]]<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>This is a tree of strings, not a string. But for many purposes, it's just as good. (It's called an iolist.) Flattening it gives "users.*,name,roles.id,roles.level,users.name AS alias"<o:p></o:p></p><p class=MsoPlainText>3> goo:unparse_return_full_fields([{users, '*'}, name, {roles, [id, level]}, {users, {name, alias}}]).<o:p></o:p></p><p class=MsoPlainText>{"users.*,name,roles.id,roles.level,users.name AS alias", [roles,users]}<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>You will note that the functions above don't have any use for reversing a list. And I must repeat that for many purposes, such as sending text to another OS process, there isn't any *need* to flatten the tree of strings.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>Even in your code,<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>> parse_return_full_fields(FullFieldsSpecs, Separator, OperatorFinder) -><o:p></o:p></p><p class=MsoPlainText>> {ParsedFields, TableNames} =<o:p></o:p></p><p class=MsoPlainText>> parse_full_fields2(FullFieldsSpecs, [], [], OperatorFinder),<o:p></o:p></p><p class=MsoPlainText>> {string:join(lists:reverse(ParsedFields), Separator), TableNames}.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>there isn't actually any need to do this:<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText> my_reverse_join([X|Xs], Sep) -><o:p></o:p></p><p class=MsoPlainText> my_reverse_join(Xs, X, Sep);<o:p></o:p></p><p class=MsoPlainText> my_reverse_join([], _) -><o:p></o:p></p><p class=MsoPlainText> "".<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText> my_reverse_join([], Acc, _) -><o:p></o:p></p><p class=MsoPlainText> Acc;<o:p></o:p></p><p class=MsoPlainText> my_reverse_join([Y|Ys], Acc, Sep) -><o:p></o:p></p><p class=MsoPlainText> my_reverse_join(Ys, Y++Sep++Acc, Sep).<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>9> goo:my_reverse_join(["harry","deacon","thom","avery"]).<o:p></o:p></p><p class=MsoPlainText>"avery,thom,deacon,harry"<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>We see two ideas here which are likely to be applicable to your code in context.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>(1) It may be possible to *eliminate* a call to lists:reverse/1<o:p></o:p></p><p class=MsoPlainText> by fusing it with the function the result is being passed to.<o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p><p class=MsoPlainText>(2) It may be possible to *eliminate* appends (++) by constructing<o:p></o:p></p><p class=MsoPlainText> an iolist (a tree of strings) instead of a string. For example,<o:p></o:p></p><p class=MsoPlainText> io:put_chars/2 wants a unicode:chardata().<o:p></o:p></p><p class=MsoPlainText> <a href="http://www.erlang.org/doc/man/unicode.html#type-chardata"><span style='color:windowtext;text-decoration:none'>http://www.erlang.org/doc/man/unicode.html#type-chardata</span></a><o:p></o:p></p><p class=MsoPlainText> <a href="http://www.erlang.org/doc/man/io.html#put_chars-2"><span style='color:windowtext;text-decoration:none'>http://www.erlang.org/doc/man/io.html#put_chars-2</span></a><o:p></o:p></p><p class=MsoPlainText><o:p> </o:p></p></div></body></html>