具有列表理解的多重分配

时间:2018-01-26 12:18:37

标签: python python-2.7 list-comprehension

我想知道我是否可以使用一个列表理解来分配多个列表。我无论如何都无法理解语法。

所以,而不是......

xs = [item.km for item in data]
ys = [item.price for item in data]

我想做...

xs, ys = [km, price for km, price in data]
# or...
xs, ys = [item.km, item.price for item in data]

但这会引发语法错误,我似乎无法找到错误。

即使看起来很明显,数据如下......

for elem in data:
    print elem
# outputs (this is a namedtuple) :
# mileage(km=22899.0, price=7990.0)
# mileage(km=48235.0, price=6900.0)
# mileage(km=54000.0, price=7990.0)
# mileage(km=60949.0, price=7490.0)
...

3 个答案:

答案 0 :(得分:6)

如果我正确理解了您的结构,您需要使用带有star-argument的zip()来转置您的数据:

xs, ys = zip(*[(km, price) for km, price in data]) 

答案 1 :(得分:3)

单个列表理解产生一个列表。您已尝试使用多个赋值将结构[(a,b), (a,b), (a,b)]的列表分配给两个变量,但这不起作用,因为条目数不匹配。您可以生成对组件的列表:

kms = [item.km for item in data]
prices = [item.price for item in data]

但这会对列表data进行两次处理。如果避免这种情况非常重要,我们可以并行构建两个列表,但这仍然不是一个单一的理解:

kms, prices = [], []
for item in data:
    kms.append(item.km)
    prices.append(item.price)

通过预先分配列表,您可以在内存管理器上实现更低的负载:

kms, prices = [None]*len(data), [None]*len(data)
for i,item in enumerate(data):
    kms[i]=item.km
    prices[i]=item.price

但最有可能的是,你最好用联合方式处理数据,比如numpy或pandas。

可以使用折叠来生成两个列表,其中包含来自一个解释的输入,但在常见的Python实现中,它既复杂又低效。

答案 2 :(得分:1)

简单的答案就像其他人已经指出的那样:列表理解产生一个列表

但是,正如@Chris_Rands建议的那样,您可以使用zip转置数据。我会调整它并使用生成器使其快一点。

xs, ys = zip(*((item.km, item.price) for item in data))

问题是上面会在数据集上多次迭代,以产生你期望的结果。使用普通for迭代将表现得更好,因为Yann's answer状态(答案有更好的选择):

xs, ys = [], []
for item in data:
    xs.append(item.km)
    ys.append(item.price)

有时我们需要牺牲一些有利于表现的东西。在这种情况下:

  • zip是一个很棒的工具,但它并不是真正意义上的。对于不知道用例的人来说,该片段不易读取,并且使用生成器也很慢(O(2 * n ^ 2)或可能 O(n ^ 2)没有经过测试)。
  • 使用普通for将使您的代码真正更快(O(n)),这可能真的很重要,具体取决于data的大小。