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: SortedDict key function based on values #21
Comments
How about this recipe:
Example usage:
|
When I try to add an element to the CustomSortedDict I get a KeyError on the line return self._key(key, self._dict[key]) The stack trace above that is line 180 in sorteddict.py and line 65 in sortedlistwithkey.py |
Hmm, yeah. That's a problem. In that particular case, the dict doesn't yet contain the item when the key function is computed. I'm afraid other parts of the code assume that the key function operates only on the key and not the item or value. You might try the PriorityDict at https://github.com/grantjenks/prioritydict/blob/master/prioritydict.py which orders elements by value. I haven't published it to PyPI yet but it's pretty far along. |
Actually, if you override just a couple more methods, I think it works. You need to override the getitem and setitem methods:
|
That definitely fixed the error, however deleting things doesn't seem to be working. That might be due to my code however, I'll keep you posted. Thank you so much for all the help. |
Yep, that was my bug, it seems like everything is working perfectly now. Thank you so so much. Because I'm using this code in a project, how would you like to be credited and are there any license restrictions on the code you wrote in this issue? |
Thanks for asking. Same license as for the project. Source available under Apache 2 License: http://www.grantjenks.com/docs/sortedcontainers/#sortedcontainers-license |
I think to make this recipe work you'll also need to override the copy methods. Here's the whole pattern, updated: import sortedcontainers as sc
class KeyWrapper(object):
"Wraps a key function and applies with `(key, value)` item."
def __init__(self, func, _dict):
self._func = func
self._dict = _dict
def __call__(self, key):
"Apply key function to `(key, value)` item."
return self._func(key, self._dict[key])
class CustomSortedDict(sc.SortedDict):
"Requires a key function that accepts two arguments: key, value."
def __init__(self, *args, **kwargs):
assert len(args) > 0 and callable(args[0])
args = list(args)
key = self._original_key = args[0]
args[0] = KeyWrapper(key, self)
super(CustomSortedDict, self).__init__(*args, **kwargs)
def __delitem__(self, key):
"""
Remove ``d[key]`` from *d*.
Raise KeyError if *key* is not in the dictionary.
"""
if key not in self:
raise KeyError(key)
self._list_remove(key)
self._delitem(key)
def __setitem__(self, key, value):
"""Set `d[key]` to *value*."""
if key in self:
self._list_remove(key)
self._delitem(key)
self._setitem(key, value)
self._list_add(key)
def copy(self):
"""Return a shallow copy of the sorted dictionary."""
return self.__class__(self._original_key, self._load, self.iteritems())
__copy__ = copy |
In all the usage I've been making of the previous recipe it's been working perfectly fine, so I have no idea how necessary that is. |
Well assuming you've never called |
I've published this recipe as part of a new package named |
I would like to be able to have a SortedDict where the sorting is determined by the value being added, or some combination of the key and the value. Basically, the ability for me to provide a key function that takes two arguments.
The text was updated successfully, but these errors were encountered: