如何在Python列表推导式中生成重复元素?迭代器能否互相引用?
嘿,好问题!咱们一步步来拆解你的疑问:
当然可以,但要注意循环的嵌套顺序——列表推导式里的多个迭代器是按从左到右的顺序对应外层到内层循环的,所以后面的迭代器可以引用前面已经定义的变量,但反过来不行。
举个实际的例子:如果你想生成每个x对应的0到x-1的数对,完全可以这么写:
a = [2, 3, 4] result = [(x, y) for x in a for y in range(x)] # 输出结果:[(2, 0), (2, 1), (3, 0), (3, 1), (3, 2), (4, 0), (4, 1), (4, 2), (4, 3)]
这里内层的range(x)就引用了外层迭代的x变量,完全合法。但如果反过来写[(x,y) for y in range(x) for x in a]就会直接报错,因为x还没被定义就被用到了。
针对你的例子arr = [1,2,3,4],其实不用绕弯子查arr.index(x)——因为x本身就是当前迭代的元素,直接重复它就行,比你原来的写法简洁多了。
下面分两种常见需求给出方案:
- 需求1:每个元素重复两次,组成子列表(比如得到
[[1,1], [2,2], [3,3], [4,4]])
直接写:
arr = [1,2,3,4] dubs = [[x, x] for x in arr] # 如果要通用重复n次,可以用 [x]*n dubs_n = [[x]*3 for x in arr] # 得到 [[1,1,1], [2,2,2], [3,3,3], [4,4,4]]
你原来的写法[[x] + [arr[arr.index(x)]] for x in arr]虽然能得到相同结果,但完全没必要——arr[arr.index(x)]其实就是x本身,而且如果arr里有重复元素,index()只会返回第一个匹配项的索引,但因为x就是当前元素,结果还是对的,只是多做了无用功。
- 需求2:平铺的重复元素列表(比如得到
[1,1,2,2,3,3,4,4])
这时候可以用嵌套迭代器,把每个元素重复指定次数后平铺:
arr = [1,2,3,4] flattened_dubs = [x for x in arr for _ in range(2)] # 要重复n次就把range(2)改成range(n)
这里的_是占位符变量,因为我们不需要用到它的值,只是用来控制循环次数。
小提醒
如果你的列表里有可变元素(比如子列表),用[x]*n要小心——这会创建n个指向同一个对象的引用。比如arr = [[1], [2]],[[x]*2 for x in arr]会得到[[[1], [1]], [[2], [2]]],此时修改其中一个子列表会影响另一个。这种情况下可以用列表推导式生成新对象:[[x.copy() for _ in range(2)] for x in arr](如果x是列表的话)。
内容的提问来源于stack exchange,提问作者JeffreyC

