问题陈述
目前我正在用 Python 实现 A* 搜索算法(针对特定问题进行了大量修改)。作为问题的组成部分,我需要快速访问后进先出顺序中的最小启发式值。 Python 的优先级队列看起来最好。我的数据结构已经是具有父关系的字典列表,所以能够对它们进行排序会很好。但是,我似乎很难这样做。例如,我有一个新字典的例子:
queue = PriorityQueue() # Could be instantiated based on an existing list of dicts
exampleDict = {"x": 10, "y": 20, "f": 123, "parent":{}}
我希望能够通过元组或类似形式将这本字典插入优先级队列
queue.put((exampleDict["f"], exampleDict))
请注意,我无法尝试使用外部库,因此我正在寻找更原生的 py3 解决方案。
发生了什么
我已经尝试了所有对我来说显而易见的解决方案。阅读文档,我发现 Python 允许一个元组,其中元组中的第二项是字典,第一项是优先级:
parent = {'x': 0, 'y': 0, 'parent': False, 'f': 0, 'g': 50, 'wallPassed': 0}
something = (1, {'h': 9, 'x': 0, 'y': 1, 'parent': parent, 'f': 60, 'g': 51, 'wallPassed': 0})
somethingElse = (1, {'h': 9, 'x': 1, 'y': 0, 'parent': parent, 'f': 60, 'g': 51, 'wallPassed': 1})
test = PriorityQueue()
test.put(something)
test.put(somethingElse)
它在插入一个值时有效,但是在我插入另一个值的那一刻它失败了
Traceback (most recent call last):
File "test.py", line 8, in <module>
test.put(somethingElse)
File "C:\Users\champloo11\AppData\Local\Programs\Python\Python35-32\lib\queue.py", line 143, in put
self._put(item)
File "C:\Users\champloo11\AppData\Local\Programs\Python\Python35-32\lib\queue.py", line 227, in _put
heappush(self.queue, item)
TypeError: unorderable types: dict() < dict()
有什么可以做的吗?似乎没有太多关于问题的文档记录方式,或者在没有 frozendict 的情况下解决问题。
原文由 Daymon Schroeder 发布,翻译遵循 CC BY-SA 4.0 许可协议
问题是字典在 Python 中是不可排序的类型。也就是说,如果您尝试运行以下内容:
你会得到一个
TypeError
。您尝试使用的技巧是将字典包装成一个元组,该元组的第一个元素 是 可排序的——类似于数字。然后我们可以比较它们:现在看看 Python 如何比较元组是值得的。首先,Python 比较每个元组的第一个条目。在这种情况下,
1 < 2
,Python 返回True
。但是,如果第一个条目没有排序——假设它们相同——Python 就会去比较 第二个 条目。例如所以在你上面的例子中发生的是你有两个元组具有相同的第一个条目,每个的第二个条目是一个字典。因此 Python 比较前两个条目,无法确定它们的顺序,然后尝试比较第二个条目,它们是字典并且无法排序。在一个例子中,
正如我们在上面看到的那样,工作得很好。但是更改右侧元组的第一个条目会出现错误:
那么什么是正确的解决方案呢?如果你有办法为每个字典分配一个 唯一的 优先级,那么元组方法就会起作用。但是每个元组的第一个条目必须是唯一的!否则 Python 将求助于比较第二个条目,它们是字典,您将再次遇到同样的问题。
如果这不可能或不可取,那么我们必须为 Python 提供一种比较这两个词典的方法。一种方法是创建一个
PriorityEntry
类并定义其__lt__
方法。要创建此类的实例,您需要提供可以排序的优先级和不需要排序的数据。然后__lt__
仅按优先级而非数据对类的两个实例进行排序。那是:所以
或者,使用您的数据:
现在将在不引发错误的情况下运行。