Skip to content

Commit

Permalink
Add set_in() and update_in()
Browse files Browse the repository at this point in the history
Closes #29
  • Loading branch information
Suor committed Mar 31, 2015
1 parent eb5a16a commit 655c48e
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 1 deletion.
19 changes: 19 additions & 0 deletions docs/colls.rst
Expand Up @@ -192,6 +192,25 @@ Dict utils
get_in({"a": {"b": 42}}, ["c"], "foo") # -> "foo"


.. function:: set_in(coll, path, value)

Creates a dictionary with a ``value`` set at specified ``path``. Original collection is not changed::

get_in({"a": {"b": 42}}, ["a", "b"], 10)
# -> {"a": {"b": 10}}

get_in({"a": {"b": 42}}, ["a", "c"], 10)
# -> {"a": {"b": 42, "c": 10}}


.. function:: update_in(coll, path, update, default=None)

Creates a dictionary with a value at specified ``path`` updated::

update_in({"a": {}}, ["a", "cnt"], inc, default=0)
# -> {"a": {"cnt": 1}}


Data manipulation
-----------------

Expand Down
15 changes: 14 additions & 1 deletion funcy/colls.py
Expand Up @@ -18,7 +18,8 @@
'walk', 'walk_keys', 'walk_values', 'select', 'select_keys', 'select_values', 'compact',
'is_distinct', 'all', 'any', 'none', 'one', 'some',
'zipdict', 'flip', 'project', 'izip_values', 'izip_dicts',
'where', 'pluck', 'pluck_attrs', 'invoke', 'get_in']
'where', 'pluck', 'pluck_attrs', 'invoke',
'get_in', 'set_in', 'update_in']


### Generic ops
Expand Down Expand Up @@ -229,6 +230,18 @@ def get_in(coll, path, default=None):
return default
return coll

def set_in(coll, path, value):
if not path:
return value
else:
copy = coll.copy()
copy[path[0]] = set_in(copy.get(path[0], {}), path[1:], value)
return copy

def update_in(coll, path, update, default=None):
value = update(get_in(coll, path, default))
return set_in(coll, path, value)


def where(mappings, **cond):
match = lambda m: all(m[k] == v for k, v in cond.items())
Expand Down
24 changes: 24 additions & 0 deletions tests/test_colls.py
Expand Up @@ -221,6 +221,30 @@ def test_get_in():
assert get_in(d, ["a", "b"]) == "c"
assert get_in(d, ["a", "f", "g"]) == "h"

def test_set_in():
d = {
'a': {
'b': 1,
'c': 2,
},
'd': 5
}

d2 = set_in(d, ['a', 'c'], 7)
assert d['a']['c'] == 2
assert d2['a']['c'] == 7

d3 = set_in(d, ['e', 'f'], 42)
assert d3['e'] == {'f': 42}
assert d3['a'] is d['a']

def test_update_in():
d = {'c': []}

d2 = update_in(d, ['a', 'b'], inc, default=0)
assert d2['a']['b'] == 1
assert d2['c'] is d['c']


# These things are named differently in python 3
try:
Expand Down

0 comments on commit 655c48e

Please sign in to comment.