2016-11-21 66 views
1

我問的原因是在合併各種數據結構,字典,列表,字符串。任何方式將此循環轉換爲列表理解?

bffer = "" 
dict_size = 128 
for character in string: 
    appnd_bffer = bffer + character 
    if appnd_bffer in codebook: 
     bffer = appnd_bffer 
    else: 
     output_list.append(codebook[bffer]) 
     codebook[appnd_bffer] = dict_size 
     dict_size += 1 
     bffer = character 

我是新來列出內涵,所以我可以真正使用的解釋,如果它是可能的。乾杯。

+8

爲什麼需要這個被轉換成一個列表理解?這真的會傷害可讀性。 –

+0

你爲什麼想要?如果由某種惡魔巫術,它是可以堵塞所有到一個列表理解,這將是完全不可讀。 –

+0

'[do_everything_youre_doing_in_the_loop(字符),用於字符串的字符]'...?這是太多的代碼內聯成一個修真... – deceze

回答

6

只是爲了讓你知道爲什麼它是一個確實不好主意嘗試和填充你的LZW壓縮器的循環列表理解,我已經寫了一些瘋狂的代碼,這樣做。

它使用了一些比較狡猾的技巧,它不適用於Python 3,因爲在Python 3中,列表理解運行在它自己的範圍內;在Python 2中,列表理解運行在周圍代碼的範圍內。這意味着我將原始緩衝區傳遞到列表組件中的技巧在Python 3中不起作用。

首先,這是您的原始代碼包裝在函數中,其中包含一些變量名稱更改以及一些添加演員陣容,使其成爲一個可運行的,可測試的例子。

from __future__ import print_function 

def lzw_compress_Boa(data): 
    dict_size = 128 
    codebook = {chr(i): i for i in range(dict_size)} 

    output_list = [] 
    oldbuff = "" 
    for ch in data: 
     newbuff = oldbuff + ch 
     if newbuff in codebook: 
      oldbuff = newbuff 
     else: 
      output_list.append(codebook[oldbuff]) 
      codebook[newbuff] = dict_size 
      dict_size += 1 
      oldbuff = ch 
    return output_list 

data = 'this data is this data' 

output_list = lzw_compress_Boa(data) 
print(output_list) 
print(len(data), '->', len(output_list)) 

輸出

[116, 104, 105, 115, 32, 100, 97, 116, 97, 32, 130, 32, 128, 138, 133] 
22 -> 15 

,我們實際上並不需要保持碼本的尺寸在一個單獨的變量。像所有Python的內置容器類型一樣,字典跟蹤其大小,我們可以使用len()函數來獲取它。這條線

codebook[newbuff] = dict_size 
dict_size += 1 

:所以我們可以替換這些2線

codebook[newbuff] = len(codebook) 

現在,這裏是一個使用列表理解瘋狂的版本。記住孩子,不要試試這個在家裏! :)

def lzw_compress_crazy(data): 
    dict_size = 128 
    codebook = {chr(i): i for i in range(dict_size)} 

    def magic(oldbuff, ch): 
     newbuff = oldbuff + ch 
     if newbuff in codebook: 
      return [(newbuff, None)] 
     else: 
      codebook[newbuff] = len(codebook) 
      return [(ch, codebook[oldbuff])] 

    oldbuff = "" 
    return [result for ch in data 
     for oldbuff, result in magic(oldbuff, ch) if result] 

請注意,這個版本不僅比我發佈的第一個版本更難讀取,它的效率也不高。正如我在開始時所說的那樣,它的便攜性較差,而且它使用了一些永遠不會用於嚴肅代碼的完全狡猾的技巧。

列表理解是冷靜,一旦你已經習慣了他們,他們可以使你的代碼更簡潔,它可以幫助可讀性,只要你不要試圖做太多在其中。列表比較是比「傳統」風格for循環使用.append等效代碼效率更高,但它們不是魔術,並使用難以理解的列表理解,而不是AA漂亮清晰可讀傳統for環路 Python的。

+0

懶惰。我想看看'[b for Popen(['working_c_implementation'],stdin = PIPE,stdout = PIPE).communicate(data)[0]]'。 –

+0

@ZeroPiraeus LOL。我想要保持這個狀態在一個可迭代的類中,但決定不要太瘋狂。 :) –

2

不,因爲它包含構成列表的列表以外的其他表達式(例如dict_size += 1),所以不能編入列表理解。這些表達式在列表理解中沒有用處,因爲理解的唯一目的是創建該對象。有什麼可以幫助你創建一個單獨的函數,包含循環的單個迭代的邏輯,然後在循環中使用該函數。

+1

它仍然可以完成。但它不會被讀取。例如,'dict_size'值可以由'itertools.count()'對象處理。 –

+0

謝謝你的回答。快速的問題,會增加一個功能,並做你說的是對代碼的積極改變?無論是在可讀性/「清潔度」方面? – Boa

+0

@Boa是的,這通常是很好的做法,但通常取決於你的具體情況 – Noah

8

該循環目前取決於能夠分配給bffer。因爲賦值是陳述,並且列表解析只能包含表達式,將其轉換爲列表理解將需要很多難以跟蹤的可變對象。因此,將其轉換爲列表理解將導致無法讀取的混亂,沒有任何明顯的好處(任何移除list.append()調用的速度優勢將被可變對象操縱所抵消)。

+1

有沒有人做過關於*無法理解的明顯的雙關語*但是......? – deceze

+1

@deceze:我試圖避免它! :-D –

+0

出於好奇,有什麼辦法可以看到一個全面的例子嗎?我認爲這是不可能的 – Noah