Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add del_in() to colls.py for symmetry and completeness #102

Closed
ruancomelli opened this issue Aug 30, 2021 · 3 comments
Closed

Add del_in() to colls.py for symmetry and completeness #102

ruancomelli opened this issue Aug 30, 2021 · 3 comments

Comments

@ruancomelli
Copy link
Contributor

ruancomelli commented Aug 30, 2021

EDIT by @Suor. I changed omit_in to del_in() in the title, since it matches better with a particular need - see discussion. The text below stays as is and thus still will refer to the proposed function as omit_in.

I recently had to add another function to the family of get_in, update_in and set_in from the funcy.colls module. The goal here is to omit the key-value pair at path. I think that the implementation and docstring speak by themselves:

def omit_in(coll, path):
    '''Create a copy of `coll` with value omitted at `path`.

    For example:
    >>> omit_in({'a': {'b': 0, 'c': 1}}, ['a', 'c'])
    {'a': {'b': 0}}
    >>> omit_in({'a': {'b': 0, 'c': 1}}, ['a'])
    {}
    >>> omit_in({'a': {'b': 0, 'c': 1}}, ['c'])
    {'a': {'b': 0, 'c': 1}}
    '''
    *path, key = path

    current = get_in(coll, path, {})
    omitted = omit(current, {key})

    return set_in(coll, path, omitted)

This is almost like omit({'a': 0, 'b': 1}, 'a'), but it also works with deep paths.

If you are interested in adding this to Funcy, I would gladly submit a PR 😄
And, if that is the case, some points I'd like to ask you what exceptions should be raised in case: (1) path is empty, so that *path, key = path fails with ValueError: not enough values to unpack (expected at least 1, got 0); and (2) path is not a valid path for the collection coll (see 3rd example in the docstring).

@Suor
Copy link
Owner

Suor commented Aug 30, 2021

There are a couple of issues with this:

  • the API does not permit omitting several things, like omit() does.
  • what about of projecting instead of omitting? Do we also need project_in()?
  • what if we want to filter keys by some predicate? Do we need select_keys_in()?

So we come to a combinatoric explosion, which is traditionally solved with composition. In this case we can pass things to update_in():

update_in({'a': {'b': 0, 'c': 1}}, ['a'], rpartial(omit, {'c'}))

# if we expect path may not always be present
update_in(coll, path, rpartial(omit, keys), default={})

# several things to omit
update_in(coll, path, rpartial(omit, {'c', 'd'}))

# whitelist keys on path
update_in(coll, path, rpartial(project, {'a', 'b'}))

# ...

If you happen to do any particular of these operations a lot you may write a one-line helper. I am not sure that one should be included into funcy just yet.

@ruancomelli
Copy link
Contributor Author

Wow, I think I just didn't spend enough time toying around with update_in to realize how powerful it is. Even set_in is defined in terms of update_in. Very clever!
I would close this issue now since I agree with you that it doesn't seem worth the trouble, but there's still something bothering me here:

  • if you wish to do d.get(...) or d[...] in a deep/nested collection, you use get_in
  • if you wish to do d[...] = ... in a deep/nested collection, you use set_in
  • if you wish more general operations, perhaps update_in is the answer

So, loosely speaking, we have dict.__getitem__ and dict.__setitem__ available through get_in and set_in. However, the analogous to del d[...] (or dict.__delitem__) is still missing. I know that it can be easily implemented using update_in (as you showed), but then also can set_in. It was this "del_in" analogous that I had in mind and felt that was missing in funcy when I wrote omit_in.

Having the complete set of basic dict operations would be nice, but I also think that it may indeed be too much trouble for too little value (since nobody else seemed to need this feature up to now). I'll leave this issue open for now if you wish to add any closing remarks, but I'm satisfied with tweaking update_in.

@Suor
Copy link
Owner

Suor commented Aug 31, 2021

Ok, if you frame it as adding del_in() then it makes sense for completeness and symmetry. It will need to support lists though for the same reasons. I'll mark this with looking for more interest label for now. Thanks for bringing this up, I missed it somehow during the initial design.

@Suor Suor changed the title Include omit_in function in colls.py to omit key-value pairs in deeply nested collections Add del_in() to colls.py for symmetry and completeness Aug 31, 2021
@Suor Suor closed this as completed in 0f36b69 Sep 5, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants