删除列表项(如果不在其他列表中)-python

删除列表项(如果不在其他列表中)-python,python,Python,这是我的情况。 我有一个Person对象的列表 class Person(): def __init__(self, name="", age=): self.name = name self.uid = str( uuid.uuid4( ) ) self.age = age 我的UI包含一个显示这些项目的树状视图。在某些情况下,如果用户愿意,他们可以拥有同一个人的实例。我突出显示那些粗体,让用户知道是同一个人 问题 当用户删除树节点时

这是我的情况。 我有一个Person对象的列表

class Person():
    def __init__(self, name="", age=):
        self.name = name
        self.uid = str( uuid.uuid4( ) )
        self.age = age
我的UI包含一个显示这些项目的树状视图。在某些情况下,如果用户愿意,他们可以拥有同一个人的实例。我突出显示那些粗体,让用户知道是同一个人

问题 当用户删除树节点时,我需要知道是否应该从列表中删除实际对象。但是,如果正在使用该对象的另一个实例,那么我不应该删除它

我对解决方案的想法。 在执行删除操作(只删除treenode项)之前,我将收集ui中使用的所有人员

接下来,我将继续删除treeview项

接下来,获取在ui中使用的另一个objevst集合

Laslty比较两个列表并删除第二个列表中未出现的人员

如果我使用这个解决方案,我最好做一个测试,比如

for p in reversed(original_list):
    if p not in new_list:
        original_list.remove(p)
或者我应该收集uid编号来进行比较,而不是整个对象

名单可能相当大

Herr是我第一次尝试处理删除操作的代码。当你关闭应用程序时,它会保存一个json文件

这是我做删除的函数

def delete_treewidet_items(self, ctrl):
        global NODES
        root = self.treeWidget.invisibleRootItem()

        # delete treewidget items from gui
        for item in self.treeWidget.selectedItems():
            (item.parent() or root).removeChild(item)

        # collect all uids used in GUI
        uids_used = self.get_used_uids( root=self.treeWidget.invisibleRootItem() )

        for n in reversed(NODES):
            if n.uid not in uids_used:
                NODES.remove(n)

不必太担心运行时或列表的大小,您可以使用集合操作:

for p in set(original_list) - set(new_list):
    original_list.remove(p)
或筛选列表:

new_original_list = [p for p in original_list if p in new_list]

但是,再说一遍,为什么要查看整个列表?当一个项目(甚至是树中的非叶节点)被删除时,您知道删除了哪个项目,因此您可以将搜索限制在该项目上。

您可以使用以下方法比较对象:

  • 对象标识
  • 对象相等
  • 要比较对象标识,应使用内置函数id()或关键字is(使用id())。从文档:

    返回对象的“标识”。这是一个整数(或长) 整数),保证此对象的唯一性和常量 在它的有生之年。可能会出现两个生命周期不重叠的对象 具有相同的id()值

    运算符是否测试对象标识:x为y为真 当且仅当x和y是同一对象。x不是y,而是 逆真值

    例如:

    >>> p1 = Person('John')
    >>> p2 = Person('Billy')
    >>> id(p1) == id(p2)
    False
    >>> p1 is p2
    False
    
    要比较对象相等性,请使用=运算符=运算符使用eq方法测试等式。若类并没有定义这样的方法,那个么它将返回到比较对象的标识

    因此:

    或者我应该收集uid编号来进行比较 而不是整个对象

    你也会做同样的事情,因为你在课堂上没有定义情商

    若要筛选列表,请在迭代列表时不要修改列表,这是错误的。猜猜将打印什么:

    >>> a = [1, 2, 3]
    >>> b = [1, 2]
    >>> for item in a:
    ...     if item in b:
    ...         a.remove(item)
    >>> a
    [2, 3]
    
    如果要安全地执行此操作,请从后面遍历列表,如:

    >>> a = [1, 2, 3]
    >>> b = [1, 2]
    >>> for i in xrange(len(a) - 1, -1, -1):
    ...     if a[i] in b:
    ...         a.pop(i)
    2
    1
    >>> a
    [3]
    

    您没有发布足够的代码,但我可以收集到:

    import collections
    import uuid
    
    class Person():
        def __init__(self, name="", age=69):
            self.name = name
            self.uid = str( uuid.uuid4( ) )
            self.age = age
    
        def __eq__(self, other):
            return isinstance(other, Person) and self.uid == other.uid
        def __ne__(self, other): return self != other # you need this
    
        def __hash__(self):
            return hash(self.uid)
    
    # UI --------------------------------------------------------------------------
    persons_count = collections.defaultdict(int) # belongs to your UI class
    your_list_of_persons = []  # should be a set
    
    def add_to_ui(person):
        persons_count[person] += 1
        # add it to the UI
    
    def remove_from_ui(person):
        persons_count[person] -= 1
        if not persons_count[person]: your_list_of_persons.remove(person)
        # remove from UI
    
    所以基本上:

    在执行删除操作(只删除treenode项)之前,我将收集ui中使用的所有人员

    否-此信息始终作为用户界面中的模块变量可用-上面的
    人数。这样,您就不必到处复制列表

    保留创建人员的代码-然后更新您的列表(其中包含不同的人员,因此应该是一个集合)。如果这是在
    添加到\u ui
    中完成的(有意义),则应修改为:

    def add_to_ui(name, age):
        p = Person(name, age)
        set_of_persons.add(p) # if already there won't be re-added and it's O(1)
        persons_count[person] += 1
        # add it to the UI
    
    为了更进一步,您不需要原始列表,即
    persons\u count.keys()
    ,只需修改:

    def add_to_ui(name, age):
        p = Person(name, age)
        persons_count[person] += 1
        # add it to the UI
    
    def remove_from_ui(person):
        persons_count[person] -= 1
        if not persons_count[person]: del persons_count[person]
        # remove from UI
    
    你明白了吗

    编辑:这里是从我的最新迭代中删除的内容:

    def delete_tree_nodes_clicked(self):
        root = self.treeWidget.invisibleRootItem()
        # delete treewidget items from gui
        for item in self.treeWidget.selectedItems():
            (item.parent() or root).removeChild(item)
            self.highlighted.discard(item)
            persons_count[item.person] -= 1
            if not persons_count[item.person]: del persons_count[item.person]
    
    我已将我的解决方案(对链接到第一个问题的代码的重写)发布在:。这是一个很好的重构练习——看看提交消息。我在这里特别介绍这条格言:


    可能需要更多的工作,但我认为这是朝着正确方向迈出的一步-在大多数操作中也应该更快,并节省内存

    ,但如果一个子节点有一堆子节点,则仅限于删除的项会导致问题。仅仅删除已删除的节点并不表示其子节点也已删除。意味着我的列表仍将包含未使用的节点。您添加到UI的代码是什么?你的代码是什么创建了一个人并使用了同一个实例?我明白了-所以真正的问题是你有“项目”,你不能从他们那里得到人-UI列表控件的常见问题。您的控制是否允许您以某种方式将项目连接到人员?Aka您可以从
    项目
    人员
    获取信息吗?编辑:当然可以-你有一个CustomTreeNode,它基本上包装了一个perdon(为什么要调用个人数据)?根据我的答案重构你的代码,然后发回——基本上你可以删掉几行……在我在这里发帖之前,我将代码发布到了我的第一次尝试中。过来看。希望能有帮助。@JokerMartini:你应该把相关部分带到你的问题中去——没有人会免费为你阅读和调试300行代码;)更新问题,以显示有关删除的位的焦点。我在def-tk-explain中添加了注释。当我今天来到电脑前,我会试试你的解决方案。如果我的代码片段需要进一步解释,请告诉我。@JokerMartini:我在这里建立了一个回购协议来破解它:。我仍然需要一些激励,因为这是一个重写,我会给你的答案打上正确的标记,因为这是我一直在寻找的最符合逻辑的方法。我没有钱付钱给你重写它。我将更新和清理我的代码,并将其发布在github上,并在此处的原始帖子中链接到它,以便其他人可以看到它。