[erlang-patches] Add lists:find/2,3
Sean Cribbs
sean@REDACTED
Wed Nov 13 20:35:54 CET 2013
I've changed and force-pushed my pull-request to adjust the return values.
Instead of the bare element being returned, it is now wrapped in a tuple as
{value, Elem}. If nothing passes the predicate, 'false' is the new default
return value rather than 'undefined'. I believe this makes it more
consistent with other functions in the lists module, e.g. lists:keyfind/3.
Please refetch: https://github.com/erlang/otp/pull/102
On Wed, Nov 13, 2013 at 9:51 AM, Serge Aleynikov <serge@REDACTED>wrote:
> 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
>>>
>>>
>>
>
> _______________________________________________
> 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/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-patches/attachments/20131113/959de6d0/attachment.htm>
More information about the erlang-patches
mailing list