Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update a map but only when key already exists

Tags:

elixir

I have been writing a lot of elixir and one thing that keeps cropping my code is when I want to update the value of a map only if the key already exists, I end up with code like this:

def incSomething(state, key) do
  {_, state} = get_and_update_in(state.way.down.there[key], fn
    nil -> :pop
    j -> {nil, j + 1}
  end)
state
end

Sometimes there's a lot of code involved and sometimes there are nested get_and_update_ins so it gets messy.

I initially found myself wanting to use the update_in/2 macro, but it seems to function as more of an upsert than an update rather like the difference between update and replace into in sql.

Map.update/4 allows you to set a default, but doesn't allow you to not set anything. Map.update!/3 outright errors if the key is missing.

Is there a less awkward way to do this in the standard language? Or do I have to write my own?

like image 567
David McHealy Avatar asked Sep 10 '17 21:09

David McHealy


1 Answers

You can use Map.replace/3 to do exactly that - update the value of a key, only if that key exists in the map.

This function is available only since Elixir 1.5, for previous versions you'll need to implement it yourself. Fortunately, it's rather easy.

def update_existing(map, key, value) do
  case map do
    %{^key => _} -> %{map | key => value}
    %{} -> map
  end
end

Alternatively, if you want to use the function-style update you could modify it slightly:

def update_existing(map, key, fun) do
  case map do
    %{^key => old} -> %{map | key => fun.(old)}
    %{} -> map
  end
end
like image 126
michalmuskala Avatar answered Nov 01 '22 16:11

michalmuskala