用户自定义类型作为字典键

1 投票
1 回答
1403 浏览
提问于 2025-04-18 03:59

这几天我一直在琢磨哈希表和字典的概念,但一直找不到合适的解决办法。希望你们能原谅我这个初学者(可能也是重复的问题),并抽时间回答我。

在我初始化“世界”(这是解决经典的GridWorld MDP问题的一部分,但这不是重点)时,我创建了多个State的实例,每个实例都有一个独特的、能代表它的元组(row, column)。我的问题是,如何存储和引用这些实例。

更具体一点...

我用以下代码创建了几个状态(在尝试了字典、集合和NumPy数组等多种方法失败后,最终选择用列表来存储它们):

(rows, columns) = (3, 4)
s = [[] for _ in range(rows)]
for r in range(rows):
    for c in range(columns):
        s[r].append(State(r, c))

这个类的定义是:

class State:
    def __init__(self, row, col):
        self.row = row
        self.col = col

    def __hash__(self):
        return hash((self.row, self.col))

    def __eq__(self, other):
        return (self.row == other.row) & (self.col == other.col)

    # __hash__ and __eq__ are here because I know they should,
    # though I currently don't know how to use them.
    # I believe that is actually the real question here...

在我的代码后面,我想给每个状态分配一个属性neighbours,这个属性是一个列表,里面包含了在网格上与它实际相邻的状态。这里的“实际”是指这些状态不是状态的副本或某种表示,而是真正的状态本身。下面是我实现的代码,但并不是我想要的结果:

def add_neighbours(self):
    if self.row == 0:
        if self.col == 0:
            self.neighbours = [(0, 1), (1, 0)]
        elif self.col == 1:
            self.neighbours = [(0, 0), (0, 2)]
        elif self.col == 2:
            self.neighbours = [(0, 1), (1, 2), (0, 3)]
        elif self.col == 3:
            self.neighbours = [(0, 2), (1, 3)]
    elif self.row == 1:
        if self.col == 0:
            self.neighbours = [(0, 0), (2, 0)]
        elif self.col == 1:
            self.neighbours = []  # Pit, N/A
        elif self.col == 2:
            self.neighbours = [(0, 2), (1, 3), (2, 2)]
        elif self.col == 3:
            self.neighbours = [(0, 3), (1, 2), (2, 3)]
    elif self.row == 2:
        if self.col == 0:
            self.neighbours = [(1, 0), (2, 1)]
        elif self.col == 1:
            self.neighbours = [(2, 0), (2, 2)]
        elif self.col == 2:
            self.neighbours = [(2, 1), (1, 2), (2, 3)]
        elif self.col == 3:
            self.neighbours = [(2, 2), (1, 3)]

这个neighbours的定义让我可以从s中调用相关的状态,但看起来并不美观,肯定也不优雅。我想要的是类似这样的东西:

def add_neighbours(self):
    if self.row == 0:
        if self.col == 0:
            self.neighbours = [State((0, 1)), State((1, 0))]
        elif self.col == 1:
            self.neighbours = [State((0, 0)), State((0, 2))]
        elif self.col == 2:
            self.neighbours = [State((0, 1)), State((1, 2)), State((0, 3))]
etc...

其中State((r, c))是被反复调用的实际状态(或者我应该说是状态的引用)。

任何评论都将非常感谢。谢谢。

注意:我知道有一些详细的解释尝试(例如这个Stack Overflow的问题这个Python Wiki的参考),但不幸的是,我没能理解它们,只好请求更多的解释。

1 个回答

0

这是一个平面图,每个节点可以用一个矩阵来定位和索引。

你可以做的事情有:

  1. 创建一个索引结构,用来存储每个单独的单元格,这样你就可以通过坐标来引用一个单元格。
  2. 创建每个空的单独单元格,并把它们存储在这个索引结构中。
  3. 一旦每个空单元格创建完成,就把每个单元格和它的邻居连接起来。

你需要先把每个状态创建为空,因为你不能引用一个还没创建的对象。

代码示例:

# 1. Backing index
table = {}

# 2. Each State is empty.
table[(0, 0)] = State(0, 0)
table[(0, 1)] = State(0, 1)
table[(1, 0)] = State(1, 0)
table[(1, 1)] = State(1, 1)
# ...

# 3. Initialize each State.
table[(0, 0)].initialize()
table[(0, 1)].initialize()
# ...

class State:
  def initialize(self):
    if ...:
      # self.neighbours is a list of States.
      self.neighbours = [table[(x, y)], table[(a, b)], table[(p, q)]]

撰写回答