【问题标题】:List comprehension to extract multiple fields from list of tuples列表理解从元组列表中提取多个字段
【发布时间】:2019-04-03 23:25:28
【问题描述】:

我有一个元组列表

servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

我想创建一个只有前两个字段的新列表:

 [('server1', 80), ('server2', 443)]

但我看不到如何为多个元素制作列表理解。

hosts = [x[0] for x in servers]  # this works to give me ['server1', server2']

hostswithports = [x[0], x[1] for x in servers] # this does not work

我更喜欢学习 Python 方式而不是使用循环 - 我做错了什么?

【问题讨论】:

  • 循环是pythonic

标签: python tuples itertools


【解决方案1】:

您可以使用extended iterable unpacking

>>> servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
>>> [(server, port) for server, port, *_ in servers]
[('server1', 80), ('server2', 443)]

使用_ 作为一次性占位符名称是一种常见的约定。

【讨论】:

  • 这是唯一一个,仅通过查看有问题的行,我就知道发生了什么。可读性很重要:+1
  • ...对于旧版本,[(server, port) for server, port, _, _ in servers] 也同样有效。
  • @tobias_k 值得注意的是它以不同的方式处理事情:a, b, *_ 将接受具有至少两个子元素的元素。 a, b, _, _ 只接受具有 4 个子元素的元素。因此,它们在处理不符合示例的数据的方式上有所不同。但是对于符合要求的数据,它们是相同的......在 Py2.7 中你没有选择;)
  • 我看到我只是缺少括号,但我真的很喜欢这种方法的可读性
  • @TemporalWolf 当然,我认为这很清楚,但你是对的:OP 实际上从未提及列表的形状,只是需要前两个元素,所以它可能确实是不规则。
【解决方案2】:

您所做的几乎是正确的。您试图将列表中的每个元组翻译成一个新元组。但是您忘记了实际声明元组。这就是括号的作用:

hosts = [(x[0], x[1]) for x in servers]

【讨论】:

  • 谢谢 - 我可以发誓我也尝试过,但显然我没有!
  • @Bill 如果我每次这样做都有五分钱。 . .我至少可以买一顿牛排晚餐
【解决方案3】:

使用基本切片,如果您的任何列表元素没有预期数量的子元素,它的好处是不会失败。

[el[:2] for el in servers]

[('server1', 80), ('server2', 443)]

【讨论】:

    【解决方案4】:

    你可以使用itemgetter:

    from operator import itemgetter
    
    
    servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
    
    result = list(map(itemgetter(0, 1), servers))
    
    print(result)
    

    输出

    [('server1', 80), ('server2', 443)]
    

    一个更易读的替代方案如下:

    from operator import itemgetter
    
    get_server_and_port = itemgetter(0, 1)
    servers = [('server1', 80, 1, 2), ('server2', 443, 3, 4)]
    result = [get_server_and_port(e) for e in servers]
    
    print(result)  # [('server1', 80), ('server2', 443)]
    

    【讨论】:

    • 您可以简单地调用可迭代map 对象:result = list(map(itemgetter(0, 1), servers)) 上的列表构造函数,而不是基于“身份”转换的列表生成器。否则 +1 以智能使用 itemgetter
    • 一个次要的替代方法是将切片对象传递给 itemgetter:itemgetter(slice(n)) 等效于 itemgetter(0, 1, 2, ..., n-1),以防您要选择非平凡大小的索引范围。对于从第一个元素之后开始的范围或跳过索引的范围,您可以使用 2 或 3 个参数调用切片构造函数,例如下标切片表达式 (foo[start : stop : step])。
    猜你喜欢
    • 2011-07-19
    • 2014-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-03
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    相关资源
    最近更新 更多