将for循环转换为列表理解会产生错误的结果

时间:2018-09-04 04:36:59

标签: python list-comprehension

student = [['benny', 12.09], ['harry', 40.03], ['jenny', 56.03], ['garry', 56.33]]
for items in student:
    for _ in range(len(items)):
        if items[1] not in allscores:
          allscores.append(items[1])
print allscores

上面代码的输出是

[12.09, 40.03, 56.03, 56.33]

符合预期。

但是,如果我将2个for循环转换为列表理解,

allscores = [items[1] for _ in range(len(items)) if items[1] not in allscores for items in student]
print allscores

我得到:

allscores = [items[1] for _ in range(len(items)) if items[1] not in allscores for items in student]
NameError: name 'items' is not defined

我的列表理解有什么问题?

1 个答案:

答案 0 :(得分:3)

出现错误的原因是,循环的理解力与for循环的编写顺序相同。特别是

a = []
for y in z:
    for x in y:
        a.append(x)

可以改写为

a = [x for y in z for x in y]

不是

a = [x for x in y for y in z]

您可能正在考虑的语法是用于嵌套理解的:

a = [[x for x in y] for y in z]

但这会创建一个2D列表,这肯定不是您想要的2em列表。

现在要回答您的实际问题,让我们从items[1] for _ in range(len(items))开始。您实际上是对列表中的每个元素检查items[1]两次。可能已经尝试确保子列表包含两个元素,但是在显式索引元素1时将其杀死。

现在您会认为可以将理解力截断

allscores = [items[1] for items in students if items[1] not in allscores]

但是你不能。请记住,在理解完成之前,allscores是未定义的。将其预初始化为空列表也无济于事,因为在理解完成之前它将一直为空。

解决方案是使用set。它比您每次使用in中的if items[1] not in allscores运算符尝试执行的线性查找要有效得多。它也可以与生成器表达式一起使用,而不是与列表理解一起使用,以避免存储不必要的元素:

allscores = set(items[1] for items in students)

请注意缺少方括号。如果您绝对需要列表,请

allscores = list(set(items[1] for items in students))