【问题标题】:list comprehension without if but with else没有 if 但有 else 的列表理解
【发布时间】:2020-09-09 17:16:39
【问题描述】:

我的问题旨在在列表理解中使用 for 循环的 else 条件。

示例:

empty_list = []
def example_func(text):
    for a in text.split():
        for b in a.split(","):
            empty_list.append(b)
        else:
            empty_list.append(" ")

我想通过对两个 for 循环使用列表推导来使其更简洁。

但是我怎样才能通过为其中一个循环(在本例中为第二个)包含一个转义子句来做到这一点。 我知道我可以在列表理解中使用 if 和 else 。但是如果没有 if 语句,使用 else 怎么样。

有没有办法让解释器将其理解为 for 循环的转义子句?

非常感谢任何帮助!

编辑: 感谢您的回答!事实上,我正在尝试翻译摩尔斯电码。

输入是一个字符串,包含莫尔斯电码。 每个单词由 3 个空格分隔。每个单词的每个字母之间用 1 个空格隔开。

def decoder(code): 
    str_list = [] 
    for i in code.split("   "): 
        for e in i.split(): 
            str_list.append(morse_code_dic[e]) 
        else: 
            str_list.append(" ") 
     return "".join(str_list[:-1]).capitalize()

print(decoder(".. -   .-- .- ...   .-   --. --- --- -..   -.. .- -.--"))

我想把整个句子分解成单词,然后翻译每个单词。 内循环(一个词的翻译)完成后,它会启动它的转义子句else,加上一个空格,这样整个句子的结构就会被保留下来。这样,3 个空格将被转换为一个空格。

【问题讨论】:

  • 您的内部for 将始终完成,因此else 看起来它将始终运行。看起来这应该只是a.split(",") 中的一个单独条目。 empty_list = list(itertools.chain(a.split(","), [" "]))?或者只是empty_list = a.split(","); empty_list.append(" ")。我觉得你把事情复杂化了。不需要原始的 for 循环,因此将设计一个列表理解。
  • 列表推导不能使用break,因此,“常规”循环的可选else 子句在列表推导中没有意义。
  • 当你的外部 for 循环完成时,你 else 的重点是总是添加一个空格吗?
  • 我想你可以做类似[x for a in text.split() for x in list(a.split(",")) + [' ']] (未经测试)的事情,但老实说,我不确定将它写成列表组合是否是一种改进。但是,出于 Carcigenicate 所述的原因,您确实希望删除多余的 else: 行。
  • 谢谢大家。我更新了最初的问题,以便您了解我的意图。

标签: python list list-comprehension


【解决方案1】:

正如在 cmets 中所指出的,else 并没有那么大的意义,因为在 for 循环之后的else 的目的实际上是在循环正常终止时保存用于条件执行的代码(即不是通过break),你的循环总是会这样做,因此它总是被执行。

因此,这并不是对如何在列表理解中执行这个问题的真正答案,而是更多的替代方案。您可以使用两个嵌套的join 生成器表达式,一个用于句子,一个用于单词,而不是在所有单词后添加空格,然后删除最后一个空格并将所有内容连接在一起:

def decoder(code): 
    return " ".join("".join(morse_code_dic[e] for e in i.split())
                    for i in code.split("   ")).capitalize()

【讨论】:

  • 谢谢,没想过那个解决方案!事实上,我只是好奇是否可以在列表理解中使用转义子句的想法。但是看看您的解决方案,我不再认为必须需要转义子句。
  • @Jero。这绝对是正确的方法,但我添加了一个答案,展示了如何在理解中实际实现有限中断和其他功能。
【解决方案2】:

如 cmets 中所述,您的特定示例中的 else 子句毫无意义,因为它始终运行。让我们设计一个示例来研究模拟breakelse 的可能性。

取以下字符串:

s = 'a,b,c b,c,d c,d,e, d,e,f'

假设你想像以前一样用空格和逗号分割字符串,但你只想保留内部分割的元素直到第一次出现c

out = []
for i in s.split(): 
    for e in i.split(','):
        if e == 'c':
            break
        out.append(e)
    else: 
        out.append('-')

break 可以使用 iter 的神秘双参数形式来模拟,它接受可调用值和终止值:

>>> x = list('abcd')
>>> list(iter(iter(x).__next__, 'c'))
['a', 'b']

您可以通过chaining 使用['-'] 实现内部可迭代的else

>>> from itertools import chain
>>> x = list('abcd')
>>> list(iter(chain(x, ['-'])
.__next__, 'c'))
['a', 'b']
>>> y = list('def')
>>> list(iter(chain(y, ['-'])
.__next__, 'c'))
['d', 'e', 'f', '-']

请注意,chain 的位置在这里至关重要。如果您要将破折号链接到外部迭代器,它将始终被附加,不仅在未遇到 c 时:

>>> list(chain(iter(iter(x).__next__, 'c'), ['-']))
['a', 'b', '-']

您现在可以使用单个表达式模拟整个嵌套循环:

from itertools import chain

out = [e for i in s.split() for e in iter(chain(i.split(','), ['-']).__next__, 'c')]

【讨论】:

  • 如果您想了解 Python 的一些更深奥的特性,这是一个很好的学术示例。但请永远,永远不要在“真实”代码中这样做!
  • 整洁。使用takewhile 甚至可能更干净,更通用,例如作为list(takewhile("c".__ne__, chain(x, ["-"])))
  • @tobias_k。这是个好主意。我想弄清楚的是当out.append(e) 出现在if ...: break 之前时,如何模拟嵌套循环中的行为。
猜你喜欢
  • 2020-02-29
  • 2020-01-07
  • 2018-04-27
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-24
相关资源
最近更新 更多