这是我的情况。 我有一个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文件。
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)
答案 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)
您可以使用以下方式比较对象:
要比较对象标识,您应该使用内置功能 id()或关键字 (使用 id())。来自docs:
返回对象的“标识”。这是一个整数(或长整数) 整数)保证对于该对象是唯一的和常量的 在其一生中。两个具有非重叠寿命的对象可以 具有相同的id()值。
运算符是和不是对象标识的测试: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]