删除列表项,如果不在另一个列表中 - python

时间:2015-12-05 12:12:22

标签: python

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

class Person():
    def __init__(self, name="", age=):
        self.name = name
        self.uid = str( uuid.uuid4( ) )
        self.age = age

我的UI包含显示这些项目的树视图。在某些情况下,用户可以根据需要拥有同一个人的实例。我强调那些大胆的让用户知道它是同一个人。

![enter image description here

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

我对解决方案的想法。 在删除操作发生之前,只删除了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文件。

https://gist.github.com/JokerMartini/4a78b3c5db1dff8b7ed8

这是我执行删除的功能。

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)

3 个答案:

答案 0 :(得分:2)

你还没有真正发布足够的代码,但我可以从中收集:

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中使用的所有人。

不 - 您的信息始终可用作您的ui中的模块变量 - 上面的persons_count。这样您就不必复制列表了。

仍然是创建人员的代码 - 然后您的列表(包含不同的人员,因此应该是 set )应该更新。如果在add_to_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_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]

我在https://github.com/Utumno/so_34104763/commits/master发布了我的解决方案(重写与第一个问题相关的代码)。这是一个很好的重构练习 - 看一下提交消息。特别是我在这里介绍了这个词:https://github.com/Utumno/so_34104763/commit/074b7e659282a9896ea11bbef770464d07e865b7

可以使用更多的工作但是我认为它朝着正确的方向迈出了一步 - 在大多数操作中也应该更快并且节省内存

答案 1 :(得分:1)

不要过于担心列表的运行时间或大小,您可以使用set-operations:

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]

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

答案 2 :(得分:0)

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

  1. 对象标识
  2. 对象平等
  3. 要比较对象标识,您应该使用内置功能 id()或关键字 (使用 id())。来自docs:

    id function

      

    返回对象的“标识”。这是一个整数(或长整数)   整数)保证对于该对象是唯一的和常量的   在其一生中。两个具有非重叠寿命的对象可以   具有相同的id()值。

    is operator

      

    运算符是和不是对象标识的测试:x是y是真的   当且仅当x和y是同一个对象时。 x不是y得到的   反向真值。

    示例:

    >>> p1 = Person('John')
    >>> p2 = Person('Billy')
    >>> id(p1) == id(p2)
    False
    >>> p1 is p2
    False
    

    要比较对象相等性,请使用 == 运算符。 == 运算符使用 eq 方法来测试是否相等。如果类没有定义这样的方法,那么它将回退到比较对象的身份。

    所以:

      

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

    你会做同样的事情,因为你没有在你的班级中定义 eq

    过滤列表在迭代时不修改列表是不好的。猜猜将会打印什么:

    >>> 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]