2012-10-14 28 views
0

我有意見列表,其中有:pk(主鍵),parent_pk(父母的主鍵)和其他人...我想顯示他們W /尊重嵌套 - 如果評論有孩子,則顯示評論,然後顯示更多的孩子。評論是pk與其他評論'parent_pk相同的其他評論的孩子。顯示關於嵌套的項目列表

我原本會在我的Django博客中實現它,但首先我想學習如何操作。這就是爲什麼,爲了簡單起見,我創建了CLI應用程序。我知道那裏有解決問題的解決方案,但我想學會自己做。 :)

這是我的代碼現在:

class Comment(object): 
    def __init__(self, pk, parent_pk, content): 
     self.pk = pk 
     self.parent_pk = parent_pk 
     self.content = content 

    def has_children(self, comments): 
     for comment in comments: 
      if self.pk == comment.parent_pk: 
       return True 
     return False 

    def get_children(self, comments): 
     children = [] 
     for comment in comments: 
      if self.pk == comment.parent_pk: 
       children.append(comment) 
     return children 


def print_nested(comments, level=0): 
    def to_whitespaces(level): 
     if level == 0: 
      return "" 
     else: 
      return " " * (level * 2) 

    for comment in comments: 
     print to_whitespaces(level) + comment.content 
     if comment.has_children(comments): 
      print_nested(comment.get_children(comments), level + 1) 
      comments.pop(0) 

comments = [ 
    Comment(1, None, "foo"), 
    Comment(2, 1, "foo bar"), 
    Comment(3, None, "spam"), 
    Comment(4, 3, "spam cheese"), 
    Comment(5, 4, "spam cheese monty"), 
    Comment(6, None, "muse"), 
] 

print_nested(comments) 

Here's it on Sprunge.us (w/ syntax).

預期結果:

foo 
    foo bar 
spam 
    spam cheese 
    spam cheese monty 
muse 

實際結果:

foo 
    foo bar 
spam 
    spam cheese 
spam cheese monty 
muse 

正如你所看到的, spam cheese monty根本沒有縮進。任何想法爲什麼這樣?你將如何實現它?謝謝!

回答

1

當您遞歸調用print_nested時,只能使用子元素的當前元素。

所以你給spam的孩子打電話print_nested,你只能得到spam cheese

這意味着,當你在spam cheese打電話get_children,也有給它傳遞comments列表中沒有的元素,所以spam cheese monty因爲它只是作爲最外層的調用print_nested成員遇到沒有得到縮進。

如果您想要維護腳本的當前結構,則需要遞歸get_children,以便它可以無限次地查找子節點的子節點。

更好的方法是從註釋中構建一棵真正的樹,在那裏你可以實際查找父註釋而不用做列表遍歷。

,對於您的示例工作,可以很容易地轉換,而不是使用列表的樹一個簡單的方法:

class Comment(object): 
    def __init__(self, pk, parent_pk, content): 
     self.pk = pk 
     self.parent_pk = parent_pk 
     self.content = content 

    def depth(self): 
     depth = 0 
     comment = self 
     # this is just a recursive lookup converted to iterative 
     while comment.parent_pk: 
      # replace the array indexing with traversing up a tree 
      comment = comments[comment.parent_pk - 1] 
      depth += 1 
     return depth 

def print_nested(comments): 
    for comment in comments: 
     print comment.depth() * 2 * " " + comment.content 

comments = [ 
    Comment(1, None, "foo"), 
    Comment(2, 1, "foo bar"), 
    Comment(3, None, "spam"), 
    Comment(4, 3, "spam cheese"), 
    Comment(5, 4, "spam cheese monty"), 
    Comment(6, None, "muse"), 
] 

print_nested(comments) 
+0

哇,這真是太棒了!我不太明白...... 1.不是在打印函數中做遞歸,而是爲'Comment'創建新的方法,它通過'comments'列表中的所有註釋(有點奇怪,你不會將它作爲參數傳遞給'depth()'方法)並遞歸發現評論的深度? 2.如果主鍵會被搞亂(任何順序),這個解決方案是否會工作? – daGrevis

+0

@daGrevis正如我在文章和評論中提到的那樣,您應該在評論中構建一棵樹,並使用該數據結構來查找父母。這將消除對列表中評論順序的敏感性。我只是沒有爲你寫這部分,因爲我可以說明你的列表計算深度的一般方法,因爲pks和索引恰好相關。 – agf

0

當您在評論(3,無,「垃圾郵件」) 中顯示評論(4,3,「垃圾郵件奶酪」)時,您會在評論中彈出該評論。因此,當您處理註釋(5,4,「spam cheese monty」)時,父項「pk」缺失,因此結果顯示爲根

+0

所以「流行」不會在這裏做,對吧? – daGrevis

+0

您是否嘗試刪除「流行」?它仍然無法正常工作。 – agf

+0

刪除'pop'後 - http://pastie.org/5058188。我把它放在那裏,因爲無論如何,所有的孩子總是打印出來。 – daGrevis

1

你只需要一個遞歸函數,檢查孩子們,並將它們打印:

class Comment(object): 
    def __init__(self, pk, parent_pk, content): 
     self.pk = pk 
     self.parent_pk = parent_pk 
     self.content = content 



def print_nested(comments,pk=None,level=0): 
    for comment in comments: 
     if comment.parent_pk==pk: 
      print ' ' * (level * 2), comment.content 
      print_nested(comments,comment.pk,level+1) 

comments = [ 
    Comment(101, None, "foo"), 
    Comment(201, 101, "foo bar"), 
    Comment(301, None, "spam"), 
    Comment(415, 301, "spam cheese"), 
    Comment(505, 415, "spam cheese monty"), 
    Comment(622, None, "muse"), 
] 

print_nested(comments) 
+0

這需要你瀏覽每個評論的整個評論列表,給它O(n^2)的複雜性。我在答案中使用的一般方法可以很容易地改進,以提供O(n)性能。 – agf