从字典中弹出键值对的简洁方式?

9

pop是一个非常好用的函数,它能够在字典中根据已知的键名删除对应的项并返回相应的值。但如果我还想要这个键名怎么办呢?

显然,在简单的情况下,我可能只需要像这样做:

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

但是,假设我想弹出具有最低值的键值对,按照上述思路,我必须执行以下操作...

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

...这个方法很糟糕,因为我必须执行两次操作(显然我可以将min的输出存储在变量中,但我仍然不完全满意)。所以我的问题是:有没有一种优雅的方法来解决这个问题?我是否错过了一些明显的技巧?


min 函数的输出存储在一个变量中。 - JBernardo
1
@JBernardo 我曾经考虑过那个方法。显然,那是更好的方法,但我仍然觉得应该有一种更好的方法而不需要使用它。 - anon582847382
1
你可能需要一个堆,而不是一个dict。请查看heapq模块。 - chepner
2
你为什么不喜欢使用变量? - jfs
@J.F.Sebastian 我不介意使用它们,但我更愿意使用一个可以完成一次整洁动作的函数。这就是为什么我在问-我的问题似乎如此平凡,以至于我觉得,考虑到Python的声誉,应该有这样的函数。 - anon582847382
1
听起来如果有办法的话,它可能是some_dict.popitem()的可选参数 - 但文档中没有给出该参数,因此我认为不会有这样的方法。 - kratenko
3个回答

3

一个堆可以支持您描述的弹出最小值操作。不过,您需要首先从字典中创建一个堆。

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)

感谢您的回答。这对于最小值来说很好,但那只是弹出键和值的更一般问题的示例,给定某个键(如果不清楚,请原谅)。理想的解决方案将能够使用其他条件执行相同的操作。 - anon582847382
@J.F.Sebastian 噢,我知道这一点,但是在测试某些东西时,我变得有点懒惰,忘记了heap只是一个列表,其顺序适合于heapq函数,而不是独立堆类型的实例。 - chepner

3
你可以使用Python ABC来定义自己的字典对象,它提供了定义抽象基类的基础设施。然后根据需要重载Python字典对象的pop属性。请注意保留HTML标签。
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__)

演示:

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}

注意:正如 @chepner 在评论中建议的那样,你可以重写 popitem 方法,该方法已经返回键/值对。


最好重写 popitem 方法,该方法已经返回键/值对,并允许它接受一个可选的键参数。 - chepner
@chepner 是的,那样会更好。我只是展示了一种方法。 - Mazdak
1
感谢您的回复,我已接受它作为解决普遍问题的方案。 - anon582847382
我猜像JBernado建议的那样将密钥存储在变量中比实现一个全新的类更可取。 - karlson

2
这里有一个更简单的实现。
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)

因此,我们创建了一个自定义的dict,它会弹出您想要的项目并给出键值对。


1
请添加一些解释! - ρss

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接