Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions lib/elixir/lib/keyword.ex
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,49 @@ defmodule Keyword do
end
end

@doc """
Alters the value stored under `key` to `value`, but only
if the entry `key` already exists in the keyword list.

In the case a value is stored multiple times in the keyword list,
later occurrences are removed.

## Examples

iex> Keyword.replace([a: 1], :b, 2)
[a: 1]
iex> Keyword.replace([a: 1, b: 2, a: 4], :a, 3)
[a: 3, b: 2]

"""
@spec replace(t, key, value) :: t
def replace(keywords, key, value) when is_list(keywords) and is_atom(key) do
case :lists.keyfind(key, 1, keywords) do
{^key, _} -> [{key, value} | delete(keywords, key)]
false -> keywords
end
end

@doc """
Similar to `replace/3`, but will raise a `KeyError`
if the entry `key` does not exist.

## Examples

iex> Keyword.replace!([a: 1, b: 2, a: 4], :a, 3)
[a: 3, b: 2]
iex> Keyword.replace!([a: 1], :b, 2)
** (KeyError) key :b not found in: [a: 1]

"""
@spec replace!(t, key, value) :: t
def replace!(keywords, key, value) when is_list(keywords) and is_atom(key) do
case :lists.keyfind(key, 1, keywords) do
{^key, _} -> [{key, value} | delete(keywords, key)]
false -> raise KeyError, key: key, term: keywords
end
end

@doc """
Checks if two keywords are equal.

Expand Down
43 changes: 40 additions & 3 deletions lib/elixir/lib/map.ex
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ defmodule Map do

@type key :: any
@type value :: any
@compile {:inline, fetch: 2, put: 3, delete: 2, has_key?: 2}
@compile {:inline, fetch: 2, put: 3, delete: 2, has_key?: 2, replace: 3}

@doc """
Returns all keys from `map`.
Expand Down Expand Up @@ -271,11 +271,48 @@ defmodule Map do
@spec put_new(map, key, value) :: map
def put_new(map, key, value) do
case has_key?(map, key) do
true -> map
true -> map
false -> put(map, key, value)
end
end

@doc """
Alters the value stored under `key` to `value`, but only
if the entry `key` already exists in `map`.

## Examples

iex> Map.replace(%{a: 1}, :b, 2)
%{a: 1}
iex> Map.replace(%{a: 1, b: 2}, :a, 3)
%{a: 3, b: 2}

"""
@spec replace(map, key, value) :: map
def replace(map, key, value) do
case has_key?(map, key) do
true -> :maps.update(key, value, map)
false -> map
end
end

@doc """
Similar to `replace/3`, but will raise a `KeyError`
if the key does not exist in the map.

## Examples

iex> Map.replace!(%{a: 1, b: 2}, :a, 3)
%{a: 3, b: 2}
iex> Map.replace!(%{a: 1}, :b, 2)
** (KeyError) key :b not found in: %{a: 1}

"""
@spec replace!(map, key, value) :: map
def replace!(map, key, value) do
:maps.update(key, value, map)
end

@doc """
Evaluates `fun` and puts the result under `key`
in `map` unless `key` is already present.
Expand All @@ -300,7 +337,7 @@ defmodule Map do
@spec put_new_lazy(map, key, (() -> value)) :: map
def put_new_lazy(map, key, fun) when is_function(fun, 0) do
case has_key?(map, key) do
true -> map
true -> map
false -> put(map, key, fun.())
end
end
Expand Down