简体   繁体   中英

Neat way of popping key, value PAIR from dictionary?

pop is a great little function that, when used on dictionaries (given a known key) removes the item with that key from the dictionary and also returns the corresponding value. But what if I want the key as well?

Obviously, in simple cases I could probably just do something like this:

pair = (key, some_dict.pop(key))

But if, say, I wanted to pop the key-value pair with the lowest value, following the above idea I would have to do this...

pair = (min(some_dict, key=some.get), some_dict.pop(min(some_dict, key=some_dict.get)))

... which is hideous as I have to do the operation twice (obviously I could store the output from min in a variable, but I'm still not completely happy with that). So my question is: Is there an elegant way to do this? Am I missing an obvious trick here?

A heap supports the pop-min operation you describe. You'll need to create a heap from your dictionary first, though.

import heapq
# Must be two steps; heapify modifies its argument in-place.
# Reversing the key and the value because the value will actually be
# the "key" in the heap. (Or rather, tuples are compared 
# lexicographically, so put the value in the first position.)
heap = [(v, k) for k, v in some_dict.items()]
heapq.heapify(heap)

# Get the smallest item from the heap
value, key = heapq.heappop(heap)

You can define yourself dictionary object using python ABC s which provides the infrastructure for defining abstract base classes . And then overload the pop attribute of python dictionary objects based on your need:

from collections import Mapping

class MyDict(Mapping):
    def __init__(self, *args, **kwargs):
        self.update(dict(*args, **kwargs))

    def __setitem__(self, key, item): 
        self.__dict__[key] = item

    def __getitem__(self, key): 
        return self.__dict__[key]

    def __delitem__(self, key): 
        del self.__dict__[key]

    def pop(self, k, d=None):
        return k,self.__dict__.pop(k, d)

    def update(self, *args, **kwargs):
        return self.__dict__.update(*args, **kwargs)

    def __iter__(self):
        return iter(self.__dict__)

    def __len__(self):
        return len(self.__dict__)

    def __repr__(self): 
        return repr(self.__dict__)

Demo:

d=MyDict()

d['a']=1
d['b']=5
d['c']=8

print d
{'a': 1, 'c': 8, 'b': 5}

print d.pop(min(d, key=d.get))
('a', 1)

print d
{'c': 8, 'b': 5}

Note : As @chepner suggested in comment as a better choice you can override popitem , which already returns a key/value pair.

here is a simpler implementation

class CustomDict(dict):
    def pop_item(self, key):
        popped = {key:self[key]} #save "snapshot" of the value of key before popping
        self.pop(key)
        return popped

a = CustomDict()
b = {"hello":"wassup", "lol":"meh"}
a.update(b)
print(a.pop_item("lol"))
print(a)

So here we create a custom dict that pops the item you want and gives out the key-value pair

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM