2013-11-25 76 views
1

當有多個列表傳入函數時,第一個打印系統工作。但是,當傳入只有一個列表時,出現錯誤「AttributeError:'int'object has no attribute'pop'」爲什麼我的代碼不適用於單個列表,但適用於嵌套列表?

此代碼嘗試從列表中刪除一個項目以查看是否仍然彈出該項目存在於剩餘的列表中。

def check_row(p): 
    for e in p: 
     while e: 
      x = e.pop() 
      if x in e: 
       return False 
    return True 


print check_row([[8,2,3,4,5], 
       [2,3,1,5,6], 
       [4,0,2,3,1]]) 

print check_row([1,2,3,4,5]) 

非常感謝。

回答

2

您從元素中彈出該項目,而不是外部列表。如果你的元素不是列表,那麼不要試圖像這樣對待它們。

但是,您不能從外部列表中刪除項目,同時循環它並期望循環不跳轉項目。

如果你想看看發生了項目比列表中的一次,比較列表,而不是set()長度:

def check_row(row): 
    return len(row) == len(set(row)) 

這隻適用於可哈希值,嵌套的列表是不,但至少不會像你的代碼那樣改變列表。

你仍然可以使用列表掃描,但隨後至少使用list.index()限制超越當前位置的搜索開始索引:

def check_row(row): 
    for i, elem in enumerate(row): 
     try: 
      row.index(elem, i + 1) 
      return False # dupe found 
     except ValueError: 
      pass # no dupe found 
    return True 

然而,這種假設你想只測試外列表重複。在相同的代碼中支持嵌套結構和平面結構,而沒有關於每種情況下預期發生的更多細節,則要複雜得多。

+2

我很困惑...您的示例代碼將適用於平面列表的情況下,但不是嵌套列表的情況下,因爲'列表'不是哈希... – mgilson

+0

@mgilson:darn,那是真的;這將僅適用於列表中的可哈希值。 –

+0

@mgilson:但是,我懷疑OP並不意味着在嵌套列表上使用它,只發現代碼不起作用*除非他使用嵌套列表。 –

2

如果是單個(非嵌套)列表,請在元素(e)上調用.pop(),這些元素不是列表,因此可能沒有.pop方法。

1

這是因爲e是您的列表中的一個元素。在嵌套的一箇中,e是一個列表,而在第二個中,e是一個整數。因此,e.pop對於第二個無效。

你必須使其始終嵌套:

>>> print(check_row([[1, 2, 3, 4, 5]])) 
True 

這種方式,傳遞給check_row值始終是一個嵌套列表,即使它只有一個元素。

但是,至於檢查元素是否仍然在其他列表中,我會首先弄平列表,然後檢查列表中是否有重複的元素。

import collections 
def flatten(l): 
    for el in l: 
     if isinstance(el, collections.Iterable) and not isinstance(el, str): 
      for sub in flatten(el): 
       yield sub 
     else: 
      yield el 

def check_row(p): 
    flat = list(flatten(p)) 
    return len(flat) == len(set(flat)) 

這樣,check_row總是會產生你想要的結果,而忽略它的列表或嵌套列表:)

希望這有助於事實!

0

你在命名時感到困惑。您調用check_row的函數實際上會檢查行的列表,儘管該名稱存在,所以將其傳遞給單行失敗。你使用毫無意義的單字母名稱也無濟於事。讓我們重寫它更清楚:

如果你想要一個檢查單排功能,

def check_rows(rows): 
    for row in rows: 
     while row: 
      element = row.pop() 
      if element in row: 
       return False 
    return True 

現在,應該是更清楚失敗的原因:你傳入一個rowrows,所以for row in rows正在獲取元素而不是行,並且從那裏開始下坡。


你可能想要的是一個check_row功能在同一行上的作品,然後check_rows即每行調用check_row

def check_row(row): 
    while row: 
     element = row.pop() 
     if element in row: 
      return False 
    return True 

def check_rows(rows): 
    for row in rows: 
     if not check_row(row): 
      return False 
    return True 

不過說真的,我不知道知道你爲什麼想要這個功能。它破壞性地修改行,刪除每個元素直到第一個副本。你爲什麼要這樣?例如,馬亭皮特斯的解決方案更簡單,更高效,以及作爲非破壞性:

def check_row(row): 
    return len(set(row)) == len(row) 

雖然我們在這,讓我們使用all功能,而不是外在的循環爲check_rows

def check_rows(rows): 
    return all(check_row(row) for row in rows) 
相關問題