Access.find/1

57 views
Skip to first unread message

Michał Muskała

unread,
Jul 28, 2016, 10:40:27 AM7/28/16
to elixir-l...@googlegroups.com
Hello everybody,

I’d like to propose adding a new accessor function to Access - Access.find/1. It works exactly like Access.at/1, but instead of accessing an element by index (with Enum.at/1), you can provide an arbitrary function that will be used with Enum.find/2 to match the proper value.
I implemented this function in a project, since I needed it. Maybe it would be generally useful? The implementation is rather simple:

def find(fun) when is_function(fun, 1) do
fn(op, data, next) -> find(op, data, fun, next) end
end

defp find(:get, data, fun, next) when is_list(data) do
data |> Enum.find(fun) |> next.()
end

defp find(:get_and_update, data, fun, next) when is_list(data) do
case Enum.split_while(data, &(not fun.(&1))) do
{preceding, []} ->
{nil, preceding}
{preceding, [elem | following]} ->
case next.(elem) do
{get, update} -> {get, preceding ++ [update] ++ following}
:pop -> {elem, preceding ++ following}
end
end
end

defp find(_op, data, _fun, _next) do
raise "Access.find/1 expected a list, got: #{inspect data}"
end

Michał.
signature.asc

José Valim

unread,
Jul 28, 2016, 11:03:59 AM7/28/16
to elixir-l...@googlegroups.com
Why not make it a filter that applies it to all matching?
--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/434356A9-EF6A-47F9-BEEB-0C7D4054B2F1%40muskala.eu.
For more options, visit https://groups.google.com/d/optout.


--


José Valim
Skype: jv.ptec
Founder and Director of R&D

Michał Muskała

unread,
Jul 28, 2016, 11:12:40 AM7/28/16
to elixir-l...@googlegroups.com
Filter would work for my case as well, but in general those are different. Should we add both or select just one?

Michał. 

signature.asc

Peter Hamilton

unread,
Jul 28, 2016, 11:13:27 AM7/28/16
to elixir-l...@googlegroups.com
Could we see some example usage?

Michał Muskała

unread,
Jul 28, 2016, 11:35:26 AM7/28/16
to elixir-l...@googlegroups.com

> On 28 Jul 2016, at 17:13, Peter Hamilton <petergh...@gmail.com> wrote:
>
> Could we see some example usage?

My use case is basically something like that:

I have a struct with a field that holds a list of structs. Each of those nested structs has two fields: id and value. I want to insert a new value for a struct with a given id. For the sake of example, let’s say we work with plain maps:

id_to_update = 2
new_value = :d
map = %{nested: [%{value: :a, id: 1}, %{value: :b, id: 2}, %{value: :c, id: 3}], foo: :bar}
update_in(map, [:nested, Access.find(&(&1.id == id_to_update)), :value], fn _ -> new_value end)
#=> %{parties: [%{value: :a, id: 1}, %{value: **:d**, id: 2}, %{value: :c, id: 3}], foo: :bar}

Michał.
signature.asc

José Valim

unread,
Jul 28, 2016, 11:38:05 AM7/28/16
to elixir-l...@googlegroups.com
You should be using maps. :P



José Valim
Skype: jv.ptec
Founder and Director of R&D


Michał.

--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.

Michał Muskała

unread,
Jul 28, 2016, 11:42:18 AM7/28/16
to elixir-l...@googlegroups.com

> On 28 Jul 2016, at 17:37, José Valim <jose....@plataformatec.com.br> wrote:
>
> You should be using maps. :P
>

For most of the algorithm the order of those structs is very important (and ids are not plain integers - this was just an example). Using a map is not practical.

Would you suggest converting to a map, updating and converting back again? I don’t think it would be better.

Michał.

signature.asc
Reply all
Reply to author
Forward
0 new messages