【问题标题】:multiple variables in list comprehension?列表理解中的多个变量?
【发布时间】:2016-10-31 21:46:25
【问题描述】:

我想从多字段字符串列表中创建一个列表列表,并想知道是否可以在理解中这样做。

输入:

inputs = ["1, foo, bar", "2, tom, jerry"]

期望的输出:

[[1, "foo", "bar"], [2, "tom", "jerry"]]

在推导式中拆分字符串很容易:

>>> [s.split(",") for s in inputs]
[['1', ' foo', ' bar'], ['2', ' tom', ' jerry']]

但我无法弄清楚如何在理解内拆分字符串后访问列,因为它似乎需要变量赋值。以下不是有效的 Python,但说明了我正在寻找的内容:

[[int(x), y.strip(), z.strip() for x,y,z = s.split(",")] for s in inputs]
    or
[[int(v[0]), v[1].strip(), v[2].strip() for v = s.split(",")] for s in inputs]

有没有办法在理解中分配变量,以便输出可以由变量的函数组成?循环是微不足道的,但通过转换输入来生成列表确实看起来像是一项“理解力”任务。

outputs = []
for s in inputs:
    x,y,z = s.split(",")
    outputs.append([int(x), y.strip(), z.strip()])

【问题讨论】:

  • 您可以使用索引访问元素。对于[['1', ' foo', ' bar'], ['2', ' tom', ' jerry']]lst[0][0] 将是1lst[0][1] 将是foo 等等。如果您需要变量,您可能需要将它们存储为带有键的映射。
  • [ ... for x, y, z in (s.split(', ') for s in inputs)]

标签: python list-comprehension


【解决方案1】:

您可以在列表理解中使用两个 for 子句来执行此操作。第一个迭代列表中的项目。第二个迭代包含从拆分字符串派生的列表的单项列表(这是必需的,因此我们可以将其解压缩为三个单独的变量)。

[[int(x), y.strip(), z.strip()] for s in inputs for (x, y, z) in [s.split(",")]]

for 子句的顺序有点违反直觉,但它与您将其编写为嵌套 for 循环的方式相匹配。

Jon Sharpe 对嵌套推导(实际上是生成器表达式)的使用与此类似,而且可能更清晰。使用多个for 子句总是让我感到困惑。主要是想看看能不能在这里用上。

【讨论】:

  • 哇。我正在寻找一个“动态编程”问题。几率是多少:)
【解决方案2】:

感谢所有建议 - 很高兴看到各种可能的技术,以及 Python 禅宗的反例“应该有一种——最好只有一种——明显的方法。”

所有 4 种解决方案都同样漂亮,因此只为其中一种提供令人垂涎的绿色检查有点不公平。我同意#1 是最干净和最好的方法的建议。 #2 也很容易理解,但必须在推导式中使用 lambda 似乎有点不对劲。 #3 在创建带有 map 的迭代器方面很不错,但由于需要额外的迭代步骤而有一个小小的缺点。 #4 很酷地指出嵌套的 for 是可能的——如果我记得它们按“第一、第二”顺序而不是“内部、外部”顺序排列。由于#1 不是答案的形式,#4 得到了最令人惊讶的检查。

再次感谢大家。

inputs = ["1, foo, bar", "2,tom,  jerry"]

outputs1 = [[int(x), y.strip(), z.strip()] for x,y,z in (s.split(',') for s in inputs)]
print("1:", outputs1)       # jonrsharpe

outputs2 = [(lambda x, y, z: [int(x), y.strip(), z.strip()])(*s.split(",")) for s in inputs]
print("2:", outputs2)       # yper

outputs3 = [z for z in map(lambda x: [int(x[0]), x[1].strip(), x[2].strip()],[s.split(",") for s in inputs])]
print("3:", outputs3)       # user2314737

outputs4 = [[int(x), y.strip(), z.strip()] for s in inputs for (x, y, z) in [s.split(",")]]
print("4:", outputs4)       # kindall

结果:

1: [[1, 'foo', 'bar'], [2, 'tom', 'jerry']]
2: [[1, 'foo', 'bar'], [2, 'tom', 'jerry']]
3: [[1, 'foo', 'bar'], [2, 'tom', 'jerry']]
4: [[1, 'foo', 'bar'], [2, 'tom', 'jerry']]

【讨论】:

    【解决方案3】:

    如果你真的想在一行中做,你可以这样做,虽然它不是最清晰的代码(第一行是代码,第二行是输出)。

    >>> [(lambda x, y, z: [int(x), y.strip(), z.strip()])(*s.split(",")) for s in inputs]
    [[1, 'foo', 'bar'], [2, 'tom', 'jerry']]
    

    或者这个。

    >>> [(lambda x: [int(x[0]), x[1].strip(), x[2].strip()])(s.split(",")) for s in inputs]
    [[1, 'foo', 'bar'], [2, 'tom', 'jerry']
    

    编辑: 请参阅 jonrsharpe 的评论以获得最佳答案恕我直言。

    【讨论】:

    • 我正在考虑使用 lambda,但希望尽可能避免使用它 - 感谢您提供的工作示例。
    【解决方案4】:

    您可以将 map 与列表理解一起使用

    def clean(x):
       return [int(x[0]), x[1].strip(), x[2].strip()]
    
    map(clean,[s.split(",") for s in inputs])
    # Output: [[1, 'foo', 'bar'], [2, 'tom', 'jerry']]
    

    使用 lambda 函数:

    map(lambda x: [int(x[0]), x[1].strip(), x[2].strip()],[s.split(",") for s in inputs])
    

    【讨论】:

      【解决方案5】:

      另一种可能的解决方案

      >>> inputs = [[1, "foo", "bar"], [2, "tom", "jerry"]]
      >>> list_of_dicts = [{"var{}".format(k): v for k, v in enumerate(s, start=1)} for s in inputs]
      >>> list_of_dicts[0]['var1']
      1
      >>> list_of_dicts[0]['var2']
      'foo'
      

      【讨论】:

        猜你喜欢
        • 2013-01-03
        • 1970-01-01
        • 2021-11-29
        • 2020-05-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-22
        相关资源
        最近更新 更多