是否可以交换有序字典的两个键?
Posted
技术标签:
【中文标题】是否可以交换有序字典的两个键?【英文标题】:Is it possible to swap two keys of an ordered dictionary? 【发布时间】:2021-06-14 02:47:33 【问题描述】:注意:我使用的是 python 3.8.2,所以字典被认为是有序的
我正在创建一棵二叉树,并使用字典对树建模。
例如:
1:[2, 3], 2:[4, 5], 3:[], 4:[], 5:[]
在示例中,上面的树如下所示:
1
/ \
2 3
/ \
4 5
我试图模拟一些节点的“上升”,并保持字典的顺序。
我知道使用 myDict[key1], myDict[key2] = myDict[key2], myDict[key1]
是行不通的,因为 values 的位置发生了变化,而不是键。
我也在考虑使用.popitem()
删除最后一个值,直到我在 key1 或 key2 处,然后继续直到我到达另一个键,但这似乎有点困难。有没有其他方法可以做到这一点?
【问题讨论】:
默认字典是根据插入排序的。一个昂贵的选择是创建一个新字典,您首先在其中添加正确的键顺序,然后使用旧值更新新字典。因此,您的新值将被反转,但其余值将在插入时排序。类似的想法,将dict转换为元组或列表,执行交换,然后重新创建字典。 【参考方案1】:由于您只想交换两个密钥,我们可以从以下代码开始:
>>> changedDict =
>>> for key, value in myDict.items():
... if key not in (key1, key2):
... changedDict[key] = value
然后继续如下:
... elif key == key1:
... changedDict[key] = myDict[key2]
... else:
... changedDict[key] = myDict[key1]
【讨论】:
@wim 但是你能想到别的办法吗? 这并不是那么糟糕 - 正如我在回答中提到的那样,考虑到 dict 排序的限制,这是一种简单而可靠的方法。【参考方案2】:字典虽然现在保持插入顺序,但不能随意排序。如果您真的想使用字典顺序信息来构建树,我认为唯一可靠的方法是为每个交换操作构建一个新字典,复制原始字典的内容。
如果您想要一个任意排序的字典,更合理的方法是从 collections.abc.MutableMapping
继承并使用字典和其他一些数据结构(例如列表)跟踪该对象内的数据。
这听起来可能很复杂,但它可能比你想象的要简单:
from collections.abc import MutableMapping
class SuperOrdered(MutableMapping):
def __init__(self):
self.data =
self.order = []
def __setitem__(self, key, value):
if key not in self.data:
self.order.append(key)
self.data[key] = value
def __getitem__(self, key):
return self.data[key]
def __delitem__(self, key):
del self.data[key]
self.order.remove(key)
def __len__(self):
return len(self.data)
def __iter__(self):
yield from iter(self.order)
def replace_key(self, oldkey, newkey, value):
if newkey in self.data:
del self[newkey]
position = self.order.index(oldkey)
self.order[position] = newkey
self.data[newkey] = value
def __repr__(self):
return f"self.__class__.__name__(', '.join(repr(key) + ':' + repr(self.data[key]) for key in self))"
瞧——映射+“replace_key”方法应该足以让您按照您的想法构建树。
这是上面交互式提示中的类:
In [18]: aa = SuperOrdered()
In [19]: aa["a"] = 1;aa["b"] = 2;aa["c"] = 3
In [20]: aa
Out[20]: SuperOrdered('a':1, 'b':2, 'c':3)
In [21]: aa.replace_key("a", "d", 4)
In [22]: aa
Out[22]: SuperOrdered('d':4, 'b':2, 'c':3)
除了这个答案,而且超出主题:如果你想检查一个我希望“生产就绪”的树实现,我已经发布了一个作为我的extradict 包的一部分(pip 可安装)。
更新:也可以从collections.OrderedDict
继承并在那里添加replace_key
方法。该代码必须处理 OrderedDict 内部,但这并不难。
外部链接: Github modification
【讨论】:
__delitem__
方法是 O[n]
- 如果您希望它是 O[1],您可以使用相同的类,但将 self.data
中的每个值保留为一个元组,其中第一个元素是它的顺序。在所有点中,您检索值,仅返回原始值,并使用 `__delitem__. Even doing this, keep the
self.order` 列表中的顺序信息,以便您可以按所需顺序进行迭代。
在这里,我对 O(1) 实现做了一个要点:gist.github.com/jsbueno/9c215d44c2e6f0cc925385889046d6a9(如果及时显示有用,我可能会将它包含在“extradict”包中)
如果我改用collections.OrderedDict
会怎样?
collections.OrderedDict 与当前字典一样缺乏功能。它现在只是为了向后兼容。问题是:它们遵守严格的键插入顺序,并且无法以任何其他方式控制键顺序。
那么你认为collections.OrderedDict
有一天可能会从python 中删除吗?以上是关于是否可以交换有序字典的两个键?的主要内容,如果未能解决你的问题,请参考以下文章
任意一个序列,每次可交换序列中任意两个数,最少需要多少次交换可以使序列有序?