2016-11-21 31 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

相关问题