[erlang-patches] Add lists:find/2,3

Serge Aleynikov serge@REDACTED
Wed Nov 13 16:51:14 CET 2013


Thanks Steve for clarification. Though for that type of matching there's
lists:keymember/3 (*) that covers a good portion of suggested use cases, I
can see that in more complex scenarios find/2 could be useful, but is it
generic enough to warrant an addition to the lists module? If find/2 is
accepted, it seems to me that the index_of/2 prototyped in my prior email
could be another valuable candidate, as that is currently not doable via a
combination of functions in the lists module (other than by means of
lists:foldl/3 and throw, which is a bit ugly).

(*) 1> lists:keymember(a, 1, [{c, 2}, d, {e, 3}, [a,b,c], {a, 4}]).
true




On Wed, Nov 13, 2013 at 9:23 AM, Steve Vinoski <vinoski@REDACTED> wrote:

> lists:member/2 matches (using =:=) entire elements to determine whether or
> not they are present in the list, whereas the proposed lists:find/2,3
> allows the caller to pass a fun to test for element presence. The fun
> allows the caller to ignore fields of an element that's a tuple, record
> etc. for purposes of determining whether something is or is not present in
> the list. Therefore lists:member/2 can't do what the proposed
> lists:find/2,3 can do.
>
> --steve
>
>
>
> On Wed, Nov 13, 2013 at 9:08 AM, Serge Aleynikov <serge@REDACTED>wrote:
>
>> Since finding an element in the list is already doable via
>> lists:member/2, it seems to me that there's very little benefit in that
>> find/2 function.  Whereas a more valuable addition would be to find an
>> index of the element in the given list.  An example of a common use case
>> for that would be to locate a field's position in a mnesia table by name
>> (e.g. index_of):
>>
>> update_table(Table, FieldName, Value) ->
>>   Attrs = mnesia:table_info(Table, attributes),
>>   {ok, Pos} = index_of(FieldName, Attrs),
>>   R = mnesia:dirty_read(Table, Key),
>>   R1 = setelement(Pos, R, NewValue),
>>   ok = mnesia:dirty_write(Table, R1).
>>
>> index_of(Value, List) ->
>>   index_of(Value, List, 1).
>> index_of(V, [V|T], N) ->
>>   {ok, N};
>> index_of(V, [_|T], N) ->
>>   index_of(V, T, N+1);
>> index_of(_, [], _) ->
>>   false.
>>
>>
>> On Wed, Nov 13, 2013 at 5:48 AM, Thomas Järvstrand <tjarvstrand@REDACTED
>> > wrote:
>>
>>> A more generic version would be to return the first result of applying
>>> the fun to an element that does not return false. That way you can choose
>>> whether to return the actual element, the result of the computation you
>>> just or even something completely different. The user is also free to wrap
>>> the result in case he/she is worried that the return value might be `false`.
>>>
>>> Example implementation:
>>>
>>> *find(_MatchF, []) ->*
>>>
>>> *  false;*
>>>
>>>
>>>
>>>
>>> *find(MatchF, [X|Xs]) ->   case MatchF(X) of    false -> find(MatchF,
>>> Xs);    Val   -> Val  end.*
>>>
>>> Thomas
>>>
>>>
>>> 2013/10/22 Anthony Ramine <n.oxyde@REDACTED>
>>>
>>>> Forwarding to list.
>>>>
>>>> --
>>>> Anthony Ramine
>>>>
>>>> Le 22 oct. 2013 à 11:56, Anthony Ramine <n.oxyde@REDACTED> a écrit :
>>>>
>>>> > Maybe we could just have dropuntil(F, L) -> dropwhile(fun (X) -> not
>>>> F(X) end, L).
>>>> >
>>>> > Of course, the function would be written less naively to avoid
>>>> constructing a new fun.
>>>> >
>>>> > --
>>>> > Anthony Ramine
>>>> >
>>>> > Le 14 oct. 2013 à 15:52, Sean Cribbs <sean@REDACTED> a écrit :
>>>> >
>>>> >> #1: Would tagging the return value address like Masklinn mentions
>>>> address your concern? {ok, Term} | error (instead of a default value)?
>>>> >>
>>>> >> #2: Also, I considered dropwhile but it involves introducing another
>>>> fun, whereas the version I wrote is direct.
>>>> >>
>>>> >>
>>>> >> On Mon, Oct 14, 2013 at 5:28 AM, Anthony Ramine <n.oxyde@REDACTED>
>>>> wrote:
>>>> >> Hello Sean,
>>>> >>
>>>> >> I don't like this patch.
>>>> >>
>>>> >> 1/ You can't know whether an element was found or not if the list
>>>> elements are arbitrary terms.
>>>> >> 2/ I don't see why you would say people hack either foreach/2 or
>>>> foldl/3 to do that when they should just use dropwhile/2.
>>>> >>
>>>> >> A naive implementation of find/2 using dropwhile/2:
>>>> >>
>>>> >> find(F, L) ->
>>>> >>        case dropwhile(fun (E) -> not F(E) end, L) of
>>>> >>                [] -> undefined;
>>>> >>                [E|_] -> E
>>>> >>        end.
>>>> >>
>>>> >> Regards,
>>>> >>
>>>> >> --
>>>> >> Anthony Ramine
>>>> >>
>>>> >> Le 14 oct. 2013 à 02:44, Sean Cribbs <sean@REDACTED> a écrit :
>>>> >>
>>>> >>> `lists:find/2,3` returns the first element of the passed list for
>>>> which the predicate fun returns `true`. If no elements result in the
>>>> predicate being true, `undefined` (/2) or the given default value (/3) is
>>>> returned.
>>>> >>>
>>>> >>> ## Why this new feature?
>>>> >>>
>>>> >>> A common task is to select the first element from a list that
>>>> matches a condition, but there is no existing lists function or language
>>>> feature that avoids traversing the entire list, while still returning a
>>>> "safe" value. `lists:find/2,3` codifies the pattern of a tail-recursive
>>>> search for the matching item without resorting to exceptions (used to abort
>>>> `foreach/2` or `foldl/3`) and always returns either the first matching
>>>> item, or an otherwise safe value.
>>>> >>>
>>>> >>> ## Risks / uncertain artifacts
>>>> >>>
>>>> >>> It is unclear the desired order of arguments for the 3-arity
>>>> version. I have made the default value the final argument which is
>>>> consistent with `application:get_env/3` and `proplists:get_value/3`, but
>>>> most functions in lists place the `List` argument last.
>>>> >>>
>>>> >>> ## How did you solve it?
>>>> >>>
>>>> >>> Following the patterns of other functions in the lists module,
>>>> `lists:find/3` tests the predicate function against the head of the list,
>>>> returning the head if the predicate passes, or recursing over the tail if
>>>> it does not.
>>>> >>>
>>>> >>> https://github.com/erlang/otp/pull/102
>>>> >>>
>>>> >>> --
>>>> >>> Sean Cribbs <sean@REDACTED>
>>>> >>> Software Engineer
>>>> >>> Basho Technologies, Inc.
>>>> >>> http://basho.com/
>>>> >>> _______________________________________________
>>>> >>> erlang-patches mailing list
>>>> >>> erlang-patches@REDACTED
>>>> >>> http://erlang.org/mailman/listinfo/erlang-patches
>>>> >>
>>>> >>
>>>> >>
>>>> >>
>>>> >> --
>>>> >> Sean Cribbs <sean@REDACTED>
>>>> >> Software Engineer
>>>> >> Basho Technologies, Inc.
>>>> >> http://basho.com/
>>>> >
>>>>
>>>> _______________________________________________
>>>> erlang-patches mailing list
>>>> erlang-patches@REDACTED
>>>> http://erlang.org/mailman/listinfo/erlang-patches
>>>>
>>>
>>>
>>> _______________________________________________
>>> erlang-patches mailing list
>>> erlang-patches@REDACTED
>>> http://erlang.org/mailman/listinfo/erlang-patches
>>>
>>>
>>
>> _______________________________________________
>> erlang-patches mailing list
>> erlang-patches@REDACTED
>> http://erlang.org/mailman/listinfo/erlang-patches
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-patches/attachments/20131113/5fb1bf84/attachment.htm>


More information about the erlang-patches mailing list