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

Feature request: support pop! #81

Open
piever opened this issue Dec 20, 2021 · 3 comments
Open

Feature request: support pop! #81

piever opened this issue Dec 20, 2021 · 3 comments

Comments

@piever
Copy link
Contributor

piever commented Dec 20, 2021

Thanks for a really nice package!

There is a feature of julia Base Dicts that I think it's not supported easily here, namely:

  • pop!(d, key), similar to delete!(d, key) but returns the corresponding value d[key];
  • pop!(d, key, default), similar to unset!(d, key) but returns d[key] (or default if the key was absent).

Would it be possible to add overloads for those two methods for AbstractDictionary? I'm not sure what is the most efficient way to implement them, but it should be possible to implement them in general with the existing API.

@andyferris
Copy link
Owner

Thanks @piever, I think it's a good idea to have something like this (and I've definitely enjoyed using this interface with Base.Dict previously).

Part of my reluctance so far is that push! and pop! have iteration-order semantics (along with pushfirst! and popfirst!). These are part of the "dequeue" interface.

Another thing is that so far I've reserved method-space (is that a word? is now...) for multidiemsional indices so I'm not sure if the second one is going to work very well with that?

@piever
Copy link
Contributor Author

piever commented Jan 18, 2022

That's a good point, I see why push! and pop! are problematic because of the iteration order. Slightly off-topic, but I ended up wanting to use pop! (well, rather delete! and unset!) way less due to the semantics of this package, where map is extremely optimized but keys are shared, so some additional care is required.

My main use case for pop!(d, key, default) is wanting to split a dictionary in two (I'm using dictionaries to store many keyword arguments, which need to be forwarded to different functions).

One thought I had is that somehow merge! is a "multi-indices" versions of set!(d, key, value). In the same way one could have antimerge! (maybe not the best name...) as a "muti-indices" version of pop!(d, key, default) with the following behavior.

function antimerge!(d1, d2)
    d = empty(d1)
    for (key, value) in pairs(d2)
        # the two lines below are morally `d[key] = pop!(d1, key, value)`, may not be the most efficient implementation
        d[key] = get(d1, key, value)
        unset!(d1, key)
    end
    return d
end

(EDIT: I see now that this can be implemented much more efficiently using map as d and d2 have the same keys, but am keeping the code above for clarity.)

@andyferris
Copy link
Owner

andyferris commented Jan 19, 2022

Correct.

There is an analogy of merge for each of the union, intersection, setdiff and symdiff of the dictionary keys, and in these cases you might also want to combine the values in interesting ways (like mergewith!).

Another analogy is with relational (e.g. SQL) inner, left, right, outer, anti, left-anti and right-anti joins (where you are joining on equal keys). So antimerge might not be so far off the mark!

The version I have in my head is something like merge(d1, d2; left, right, both) where the keyword arguemnts are either function s or nothing (indicating to delete the key), both(x, y) defaults to (x, y) -> x (or maybe y), left defaults to identity, and right defaults to nothing. Unfortunately in the meantime (it's been in my head a while!) the mergewith function has came to exist so I'm not sure what to call it. And if you want to do the whole modify! thing you might want to include/delete keys based also on values (not just coincidence of keys).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants