【问题标题】:Python 3.8 assignment expression in a list comprehension列表推导中的 Python 3.8 赋值表达式
【发布时间】:2020-03-09 18:01:50
【问题描述】:

我是第一次尝试使用新的assignment expression,需要一些帮助。

给定三行日志输出:

sin = """Writing 93 records to /data/newstates-900.03-07_07/top100.newstates-900.03-07_07/Russia.seirdc.March6-900.12.csv ..
Writing 100 records to /data/newstates-900.03-07_07/top100.newstates-900.03-07_07/India.seirdc.March6-900.6.csv ..
Writing 100 records to /data/newstates-900.03-07_07/top100.newstates-900.03-07_07/US.seirdc.March6-900.15.csv ..
"""

目的是仅提取 StateRussiaIndiaUS)和记录数 (93,100,100)。所以想要的结果是:

[['Russia',93],['India',100],['US',100]]

这需要以下步骤才能翻译成 Python:

  • 将每一行转换为列表元素
  • 按空格分割,例如['Writing', '93', 'records', 'to', '/data/newstates-900.03-07_07/top100.newstates-900.03-07_07/Russia.seirdc.March6-900.12.csv', '..']
  • 用“/”分割第五个这样的标记并保留最后一个元素:例如Russia.seirdc.March6-900.12.csv
  • 用“.”分割该元素并保留第一个(0'th)元素,例如Russia

这是我的错误尝试:

import fileinput
y = [[ z[4].split('/')[-1].split('.')[0],z[1]] 
     for (z:=x.split(' ')) in 
     (x:=sin if sin else fileinput.input()).splitlines())]

【问题讨论】:

    标签: python python-3.8 python-assignment-expression


    【解决方案1】:

    对于它的价值,你也可以使用正则表达式来获得它,这可能会更受欢迎/更有效。

    [list(reversed(l)) for l in re.findall(r'Writing (\d+).+\/([A-Z,a-z]+)\.', sin)]
    

    或者更准确地说 (转换 int) 和可读性 (根据 cmets 中的 @chepner

    [[country, int(count)] for count, country in re.findall(r'Writing (\d+).+\/([A-Z,a-z]+)\.', sin)]
    

    【讨论】:

    • [ [country, int(count)] for count, country in ... ] 将更具可读性(并更好地匹配请求的输出)。
    • 有用的方法。我确实想将walrus 用于许多其他不适合聪明启发式的数据处理任务:但专门用于测试解析你的方式很有意义。 @chepner 的添加也很有帮助。
    • 哦,你刚刚删除了reverse(list)。我认为这也很有帮助(而不是完全失去)
    • 我删除了相反的内容,因为它更具可读性,它也使得将计数转换为 int 也更容易
    • 是的,我“明白”了——但做 reverse() 的诀窍实际上是要保留在 toolkit 中的一个额外的技巧。好吧,我已经吸收了它 - 但未来的读者会看到最终产品,而不是那个(有趣的)中间解决方案。
    【解决方案2】:

    这够好吗?

    [[(wrds := line.split())[4].split("/")[-1].split('.')[0], wrds[1]] for line in sin.splitlines()]
    

    我发现使用赋值表达式是多余的。你也可以这样做:

    [[line.split('/')[-1].split('.')[0], line.split()[1]] for line in sin.splitlines()]
    

    【讨论】:

    • 分配不是多余的:您的第二个分配split() 两次。想象一下,如果这是一项昂贵的手术。我正在奖励,因为这是一个很好的答案。其实第二个很聪明,但也有欺骗性:它利用了 '/' 只存在于最后一个空格分隔的标记中。
    • @javadba 我同意你的观点,但我的意思是在这个特定的问题上。此外,如果我的答案是您正在寻找的答案,您可以检查我的答案附近的复选标记。谢谢:)
    • 如果你有机会:我真的很想看看双重嵌套结构。考虑不要使用技巧将其折叠为单个级别:即 OP 是一个玩具示例,但目的是了解如何进行多级嵌套(真正需要多级的地方)和赋值表达式。跨度>
    • re:双重嵌套结构。您可以等待:我将创建一个单独的问题,在该问题中 not 可能会压缩级别。它将涉及对数值数据的分组和聚合操作。
    【解决方案3】:

    这是一种方法:

    results = []
    for line in sin.split('..'):
        if len(z := line.split(' ')) > 1 :
            results.append([line.split('/')[-1].split('.')[0], z[1]])
    

    【讨论】:

    • 请见上文:接受的答案在for 理解中使用它。您还可以参考链接的 PEP 文档。
    猜你喜欢
    • 1970-01-01
    • 2011-09-11
    • 2011-08-14
    • 1970-01-01
    • 2021-09-01
    • 1970-01-01
    • 2013-01-26
    • 2021-03-15
    相关资源
    最近更新 更多