2017-09-10 2 views
0

私は多くのエリクシルを書いています。私のコードをトリミングし続けるものは、キーがすでに存在する場合にのみ地図の値を更新したいときです。このようなコードで、最大:マップを更新するにはキーが既に存在するときのみ

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 

は時々関与し、それが厄介なるので、時々get_and_update_insがネストされているコードの多くがあります。

私は当初、自分がupdate_in/2マクロを使用したいたが、むしろSQLでupdatereplace intoの違いなどの更新よりもアップサートのよりとして機能するように思えます。

Map.update/4ではデフォルトを設定できますが、何も設定しないことはできません。 Map.update!/3キーが見つからない場合は、エラーが発生します。

これを標準言語で行うことはあまり厄介な方法ですか?または私は自分自身を書く必要がありますか?

+1

私が見つけた最も近いものは 'Map.replace/3'でしたが、キーと値を受け取りました。古い値を取り、新しい値を返す関数を渡すことはできません。 – Dogbert

答えて

0

は、私が実際に使用してしまったものです。私のデータ型は深くネストされているので、私はupdate_in/2のスタイルのマクロを使うことを好みます。

defmodule ReplaceIn do 

    defmacro replace_in(path, fun) do 
    quote do 
     get_and_update_in(unquote(path), fn 
     nil -> :pop 
     x -> {nil, unquote(fun).(x)} 
     end) |> elem(1) 
    end 
    end 

    def replace_in(data, keys, fun) do 
    get_and_update_in(data, keys, fn 
     nil -> :pop 
     x -> {nil, fun.(x)} 
    end) |> elem(1) 
    end 
end 

update_in/2とまったく同じように使用できます。

> require ReplaceIn 
> a = %{b: %{c: 1}} 
> ReplaceIn.replace_in(a.b[:c], fn x -> x + 1 end) 
%{b: %{c: 2}} 
> ReplaceIn.replace_in(a.b[:d], fn x -> x + 1 end) 
%{b: %{c: 1}} 
2

Map.replace/3を使用すると、マップにそのキーが存在する場合にのみ、キーの値を更新することができます。

この機能は、以前のバージョンのElixir 1.5以降でのみ使用できます。幸いにも、それはむしろ簡単です。あなたは関数スタイルの更新を使用する場合

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

また、あなたは少しそれを変更できます。

ここ
def update_existing(map, key, fun) do 
    case map do 
    %{^key => old} -> %{map | key => fun.(old)} 
    %{} -> map 
    end 
end 
+0

そのようなコード - FPの最高の並べ替え。シンプルで清潔。 –

+0

私は言いたいことは好きではありませんが、厳密に言えば、これを真に解決するには、 'get_and_update_in'のスタイルでマクロが必要です。 'update_in'マクロのソースは、私にとってはやや複雑に思えますが、できると確信しています。 –

関連する問題