首页 > 解决方案 > 嵌套字典/列表混合的Python自定义类在尝试删除空的时会自行清空

问题描述

我创建了一个自定义类来帮助跟踪 QTreeWidget 内的 QTreeWidgetItems,树有三个级别,并且项目被标识为这样 [a]、[a、b]、[a、b、c] 和 a、b , c 是 类型的变量int,[a, b, c] 标识位于 的项目tree.topLevelItem(a).child(b).child(c)

班级做什么?它将一个字符串列表作为输入,并输出一个整数列表,该列表由各个级别的元素的索引组成。

例如,假设类的一个对象包含以下“键”:

['a', 'a', 'a'],
['a', 'a', 'b'],
['a', 'a', 'c'],
['a', 'b', 'a']

如果给出以下输入,它将输出指定的输出:

['a', 'a', 'a'] -> [0,0,0]
['a', 'a', 'b'] -> [0,0,1]
['a', 'a', 'c'] -> [0,0,2]
['a', 'b', 'a'] -> [0,1,0]
['a', 'a'] -> [0,0]
['a', 'b'] -> [0,1]
['a'] -> [0]

该类有两个列表,一个名为 的列表Keys,它包含字符串,另一个名为的列表Values,该Values列表包含同一类的其他对象。

Keys列表和列表始终具有相同的Values长度和一一对应关系,这意味着对于Keys位于 index的任何键i,其对应项位于Values[i]

该类在概念上类似于嵌套dicts,尤其是defaultdict,并且我使用嵌套的两层defaultdict来创建树,但是 Python 字典没有索引,这就是该类的重点。

班上:

import json
from itertools import product

class TreeList:
    def __init__(self):
        self.Keys = list()
        self.Values = list()
    
    def add(self, k):
        if k[0] not in self.Keys:
            self.Keys.append(k[0])
            self.Values.append(TreeList())
        i = self.Keys.index(k[0])
        if len(k) > 1:
            child = self.Values[i]
            k.pop(0)
            child.add(k)
    
    def getValue(self, k, indexes=list()):
        if k[0] in self.Keys:
            i = self.Keys.index(k[0])
            indexes = indexes.copy()
            indexes.append(i)
            if len(k) == 1:
                return indexes
            child = self.Values[i]
            k.pop(0)
            return child.getValue(k, indexes)
    
    def delete(self, k):
        if k[0] in self.Keys:
            i = self.Keys.index(k[0])
            if len(k) == 1:
                self.Keys.remove(k[0])
                self.Values.pop(i)
            else:
                child = self.Values[i]
                k.pop(0)
                child.delete(k)
            self.recurRemoveEmpty()
    
    def removeEmpty(self):
        for v in self.Values.copy():
            if not v.Keys:
                i = self.Values.index(v)
                self.Values.remove(v)
                self.Keys.pop(i)
    
    def recurRemoveEmpty(self):
        for v in self.Values.copy():
            v.removeEmpty()
        self.removeEmpty()
    
    def to_dict(self):
        return {k: self.Values[i].toDict() for i, k in enumerate(self.Keys)}
    
    def pretty(self):
        return json.dumps(self.toDict(), indent=4)
    
    def clear(self):
        self.__init__()

一些例子:

tree = TreeList()
for i in product('abc', repeat=3): tree.add(list(i))
for i in product('abc', repeat=3): print(tree.getValue(list(i)))

输出:

[0, 0, 0]
[0, 0, 1]
[0, 0, 2]
[0, 1, 0]
[0, 1, 1]
[0, 1, 2]
[0, 2, 0]
[0, 2, 1]
[0, 2, 2]
[1, 0, 0]
[1, 0, 1]
[1, 0, 2]
[1, 1, 0]
[1, 1, 1]
[1, 1, 2]
[1, 2, 0]
[1, 2, 1]
[1, 2, 2]
[2, 0, 0]
[2, 0, 1]
[2, 0, 2]
[2, 1, 0]
[2, 1, 1]
[2, 1, 2]
[2, 2, 0]
[2, 2, 1]
[2, 2, 2]

问题是,如果我删除任何值,对象会意外地清空自己。

例如:

In [417]: tree.getValue(['a', 'a', 'a'])
Out[417]: [0, 0, 0]

In [418]: tree.getValue(['a', 'a', 'b'])
Out[418]: [0, 0, 1]

In [419]: tree.delete(['a', 'a', 'a'])

In [420]: tree.getValue(['a', 'a', 'b'])

In [421]:

它是由recurRemoveEmpty功能引起的,少不了removeEmpty

如果我删除这两个功能,一切正常:

In [424]: tree.getValue(['a', 'a', 'b'])
Out[424]: [0, 0, 1]

In [425]: tree.delete(['a', 'a', 'a'])

In [426]: tree.getValue(['a', 'a', 'b'])
Out[426]: [0, 0, 0]

In [427]: tree.getValue(['a', 'a', 'c'])
Out[427]: [0, 0, 1]

In [428]: tree.delete(['a', 'a', 'b'])

In [429]: tree.getValue(['a', 'a', 'c'])
Out[429]: [0, 0, 0]

In [430]:

问题是,如果没有子项,我的树会删除二级项,如果没有子项,则删除顶级项,在我的自定义类中,只有三级项会自动递减,这意味着如果从第二级项目中删除所有第三级项目,则在树中该项目将被删除,但在自定义类中该项目不会被自动删除,从而导致索引不一致,如果再次使用删除功能。

所以这removeEmpty是必要的,但它不会产生预期的结果。

预期的结果是,在上面的例子中,tree.getValue(['a', 'b', 'a'])应该[0,0,0]在 之后返回['a', 'a', 'a']['a', 'a', 'b']并被['a', 'a', 'c']删除。

这个怎么做?


我通过将删除自定义类中的项目的代码显式添加到删除树中的空项目的代码来规避了这一点。

不过,我仍然想知道如何在内部自动完成这样的事情。

标签: pythonpython-3.x

解决方案


推荐阅读