2015-12-05 138 views
3

這是我的情況。 我有一個Person對象列表。刪除列表項,如果不在另一個列表中 - python

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

我的用戶界面包含顯示這些項目的樹形視圖。在某些情況下,如果用戶願意,用戶可以擁有同一個人的實例。我強調那些大膽的讓用戶知道它是同一個人。

![enter image description here

的問題 當用戶刪除樹節點,然後我需要知道我是否應該從列表中刪除實際的對象。但是,如果正在使用該對象的另一個實例,則不應刪除它。

我對解決方案的想法。 在刪除操作發生之前,只刪除treenode項目,我將收集所有在ui中使用的人員。

接下來,我將繼續刪除樹視圖項目。

下一步是另一個在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

什麼是你的代碼添加到UI ?你創建一個人並使用同一個實例的代碼是什麼? –

+0

我明白了 - 所以真的問題是你有'物品',你不能從他們那裏得到人 - UI列表控件的常見問題。你的控制是否允許你以某種方式將物品連接到人員?又是你能從'物品'到'人'嗎?編輯:當然你可以 - 你有CustomTreeNode basicaly包裝perdon(爲什麼稱呼一個人的人數據)?根據我的答案重構你的代碼併發回 - 基本上你可以砍掉幾行... –

回答

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 

所以基本上:

BEF並刪除操作發生,只刪除treenode項目,我會收集所有用戶在ui中使用。

不 - 你有這個信息總是作爲一個模塊變量在你的UI - persons_count上面。這樣你就不必複製清單。

仍然是創建者的代碼 - 那麼你的列表(其中包含不同人所以應該是一個設置)應更新。如果這是在做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

可以使用更多的工作,但它是朝着正確的方向我想了一步 - 應該是大多數操作也更快,節省內存

+0

我發佈代碼給我的第一次嘗試之前我的職位在這裏。一探究竟。希望能幫助到你。 – JokerMartini

+0

@JokerMartini:你應該把相關的部分帶到你的問題 - 沒有人會免費閱讀和調試300行代碼;) –

+0

更新了問題,以顯示關於刪除位的焦點。我在def tk解釋中加了評論。當我今天到電腦時,我會嘗試你的解決方案。讓我知道,如果我的片段需要進一步解釋。 – JokerMartini

1

不是太擔心列表的運行時間或大小,你可以使用設置操作:

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] 

但隨後,爲什麼看在整個列表中 - 當一個項目(或者甚至樹中的非葉節點)被刪除時,您知道哪個項目被刪除,因此您可以將搜索範圍限制爲只有那個項目。

+1

但是,通過限制只刪除項目會導致問題,如果一個孩子有一堆子葉子節點。通過刪除被刪除的節點並不會以任何方式表示他們的孩子也被刪除。意味着我的列表仍將包含未使用的節點。 – JokerMartini

0

可以使用比較對象:

  1. 對象身份
  2. 對象平等

比較,你應該使用功能建設ID對象標識()或關鍵字(使用id())。從文檔:

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] 
相關問題