【问题标题】:How to maintain a set of sets?如何维护一套套?
【发布时间】:2012-07-13 21:25:18
【问题描述】:

我见过the related question,但我不能将frozenset 用于我的内组。我希望一切都是可变的。

据我了解,Python 为所有内容提供了ID,那么它为什么不能使用as its hash?我需要维护所有内部集的引用列表,即使它们发生变化。

编辑:好的,我明白为什么,但在这种情况下,它会更可取,因为我只关心引用相等,而不关心值相等。

我该怎么做?


你是 会问“为什么”,所以我会给你一些代码:

def remove_captured(self):
    all_chains = set()
    chains = Grid(self.rows, self.cols)
    for m, n, stone in self.enumerate():
        if stone == self[m - 1, n]:
            chains[m, n] = chains[m - 1, n]
            if stone == self[m, n - 1]:
                all_chains.discard(chains[m, n - 1])
                chains[m, n].update(chains[m, n - 1])
                for s in chains[m, n - 1]:
                    chains[s] = chains[m, n]
        elif stone == self[m, n - 1]:
            chains[m, n] = chains[m, n - 1]
        else:
            chains[m, n] = set()
            all_chains.add(chains[m, n])
        chains[m, n].add((m,n))
    chains._print()
    print all_chains

我基本上有一个游戏板,我想将板上的棋子分成组(或“链”)。上面的代码工作正常,直到我添加了all_chains——它创建了所有集合,但是我无法访问它创建的每个集合,而无需再次遍历整个板。

那么我如何维护它创建的所有集合的列表?请记住,我也需要删除集合(这就是为什么我想为外部集合使用另一个集合)。


将引用包装在 weakref.ref() 中也不起作用:

all_chains.add(weakref.ref(chains[m, n])) # TypeError: unhashable type: 'set'

【问题讨论】:

  • 假设您已经了解为什么可变对象不可散列,您可以将set() 子类化并创建一个__hash__() 方法,该方法返回id。那应该允许您制作成套的套装。另一种选择是对你的内部集进行哈希表示,也使用这些表示作为将它们映射到实际对象的键。
  • 一个集合的 id 没有为它做一个合理的散列的原因是包含相同值的两个集合不会有相同的散列。
  • @Wooble 有它:这里的问题是,如果你使用一个集合的 ID 作为它的哈希,你实际上不会有一个集合的集合。您将有一个套装袋,因为您可以将两个相同的内部套装插入外部容器中。
  • @Wooble:是的,好的,我明白这一点,但在这种特定情况下,我实际上关心的是引用,而不是值。
  • @Mark 如果您只关心引用,也许您应该使用集合字典,其中 k = id(set) 和 v = set。

标签: python set


【解决方案1】:

决定改用集合字典。

def remove_captured(self):
    cdict = {}
    cid = 0
    chains = Grid(self.rows, self.cols)
    for m, n, stone in self.enumerate():
        if stone == self[m - 1, n]:
            chains[m, n] = chains[m - 1, n]
            if stone == self[m, n - 1] and chains[m, n] != chains[m, n - 1]:
                del_id = chains[m, n - 1]
                cdict[chains[m, n]].update(cdict[del_id])
                for c in cdict[del_id]:
                    chains[c] = chains[m, n]
                del cdict[del_id]
        elif stone == self[m, n - 1]:
            chains[m, n] = chains[m, n - 1]
        else:
            cdict[cid] = set()
            chains[m, n] = cid
            cid += 1
        cdict[chains[m, n]].add((m, n))
    chains._print()
    pprint(cdict)

它不是很漂亮,因为我总是要在字典中查找该集合才能使用它,但它似乎有效。

输入:

0  .  W  W  W  W
1  W  B  B  B  .
2  .  .  .  W  .
3  .  B  B  W  W
4  .  .  B  W  .
   0  1  2  3  4

输出:

0 0 1 1 1 1
1 2 3 3 3 4
2 5 5 5 6 4
3 5 7 7 6 6
4 5 5 7 6 8
  0 1 2 3 4
{0: set([(0, 0)]),
 1: set([(0, 1), (0, 2), (0, 3), (0, 4)]),
 2: set([(1, 0)]),
 3: set([(1, 1), (1, 2), (1, 3)]),
 4: set([(1, 4), (2, 4)]),
 5: set([(2, 0), (2, 1), (2, 2), (3, 0), (4, 0), (4, 1)]),
 6: set([(2, 3), (3, 3), (3, 4), (4, 3)]),
 7: set([(3, 1), (3, 2), (4, 2)]),
 8: set([(4, 4)])}

【讨论】:

  • 集合列表不够用的任何原因?
  • @JoelCornett:是的。在中间,我也删除了集合(当我将两个合并在一起时)。如果我使用了一个列表,所有的索引都会被打乱,这会弄乱我所有的“引用”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
相关资源
最近更新 更多