Skip to content

Commit

Permalink
Add del_in()
Browse files Browse the repository at this point in the history
Closes #102
  • Loading branch information
Suor committed Sep 5, 2021
1 parent c7c70a9 commit 0f36b69
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 5 deletions.
2 changes: 1 addition & 1 deletion docs/cheatsheet.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Join :func:`merge` :func:`merge_with` :func:`join` :func:`join_
Transform :func:`walk` :func:`walk_keys` :func:`walk_values`
Filter :func:`select` :func:`select_keys` :func:`select_values` :func:`compact`
Dicts :ref:`*<colls>` :func:`flip` :func:`zipdict` :func:`pluck` :func:`where` :func:`itervalues` :func:`iteritems` :func:`zip_values` :func:`zip_dicts` :func:`project` :func:`omit`
Misc :func:`empty` :func:`get_in` :func:`set_in` :func:`update_in` :func:`has_path`
Misc :func:`empty` :func:`get_in` :func:`set_in` :func:`update_in` :func:`del_in` :func:`has_path`
===================== ==============================================================


Expand Down
10 changes: 10 additions & 0 deletions docs/colls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,16 @@ Dict utils
# -> {"a": {"cnt": 1}}


.. function:: del_in(coll, path)

Creates a nested collection with ``path`` removed::

del_in({"a": [1, 2, 3]}, ["a", 1])
# -> {"a": [1, 3]}

Returns the collection as is if the path is missing.


.. function:: has_path(coll, path)

Checks if path exists in the given nested collection::
Expand Down
4 changes: 4 additions & 0 deletions docs/descriptions.html
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,10 @@
<b>update_in<em>(coll, path, update, default=None)</em></b><br><br>
Creates a copy of <em>coll</em> with a value updated at <em>path</em>.
</div>
<div name="del_in">
<b>del_in<em>(coll, path)</em></b><br><br>
Creates a copy of <em>coll</em> with <em>path</em> removed.
</div>
<div name="has_path">
<b>has_path<em>(coll, path)</em></b><br><br>
Tests whether <em>path</em> exists in a nested <em>coll</em>.
Expand Down
20 changes: 19 additions & 1 deletion funcy/colls.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
'is_distinct', 'all', 'any', 'none', 'one', 'some',
'zipdict', 'flip', 'project', 'omit', 'zip_values', 'zip_dicts',
'where', 'pluck', 'pluck_attr', 'invoke', 'lwhere', 'lpluck', 'lpluck_attr', 'linvoke',
'get_in', 'set_in', 'update_in', 'has_path']
'get_in', 'set_in', 'update_in', 'del_in', 'has_path']


### Generic ops
Expand Down Expand Up @@ -293,6 +293,24 @@ def update_in(coll, path, update, default=None):
copy[path[0]] = update_in(copy.get(path[0], current_default), path[1:], update, default)
return copy


def del_in(coll, path):
"""Creates a copy of coll with a nested key or index deleted."""
if not path:
return coll
try:
next_coll = coll[path[0]]
except (KeyError, IndexError):
return coll

copy = coll.copy()
if len(path) == 1:
del copy[path[0]]
else:
copy[path[0]] = del_in(next_coll, path[1:])
return copy


def has_path(coll, path):
"""Checks if path exists in the given nested collection."""
for p in path:
Expand Down
11 changes: 8 additions & 3 deletions tests/test_colls.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,6 @@ def test_get_in():
assert get_in(d, ["a", "b"]) == "c"
assert get_in(d, ["a", "f", "g"]) == "h"


def test_get_in_list():
assert get_in([1, 2], [0]) == 1
assert get_in([1, 2], [3]) is None
Expand All @@ -263,14 +262,12 @@ def test_set_in():
assert d3['e'] == {'f': 42}
assert d3['a'] is d['a']


def test_set_in_list():
l = [{}, 1]
l2 = set_in(l, [1], 7)
assert l2 == [{}, 7]
assert l2[0] is l[0]


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

Expand All @@ -280,6 +277,14 @@ def test_update_in():
assert d2['a']['b'] == 1
assert d2['c'] is d['c']

def test_del_in():
d = {'c': [1, 2, 3]}

assert del_in(d, []) is d
assert del_in(d, ['a', 'b']) is d
assert del_in(d, ['c', 1]) == {'c': [1, 3]}
with pytest.raises(TypeError): del_in(d, ['c', 'b'])

def test_has_path():
d = {
"a": {
Expand Down

0 comments on commit 0f36b69

Please sign in to comment.