我试图用Python做一些使用以下一般过程的东西,我想知道最好的方法是什么。
首先,初始化步骤:
其次,循环通过以下内容:
作为一个简单的例子,假设我想创建一个列表列表,其中第n个列表包含从1到n的数字。我可以使用以下(愚蠢)程序。
我尝试了一些东西,但是大多数东西不仅会修改最后添加的项目,还会修改前面步骤中添加到L的项目。对于我感兴趣的特定问题,我确实设法找到一个行为正常的解决方案(至少对于小案例),但它似乎不优雅,我不知道为什么它在其他事情没有时起作用,而且我'我甚至不相信它会像大案一样表现出来。我也不相信我可以调整我的方法来解决类似的问题。我不理解这个问题,因为我在其他编程语言中编写了同样的东西而没有问题。
所以我想知道更有经验的Python程序员将如何处理这项一般任务。
(我省略了我自己的代码部分是因为我是新来的,我还没弄清楚如何在stackoverflow上输入它,但也因为它很长,我不想要帮助解决特定问题,而不是如何处理我上面描述的更一般的过程。)
答案 0 :(得分:10)
将列表对象M
添加到其他列表时,您只需添加引用;继续操纵列表M
意味着您将看到通过其他参考反映的这些更改:
>>> M = []
>>> resultlist = []
>>> resultlist.append(M)
>>> M is resultlist[0]
True
>>> M.append(1)
>>> resultlist[0]
[1]
>>> M
[1]
请注意M is resultlist[0]
为True;它是同一个对象。
您需要添加M
的副本:
resultlist.append(M[:])
此处的整个切片([:]
表示从头到尾切片)创建一个新列表,其中包含M
内容的浅表副本。
从不断更改的起点L
生成一系列M
的通用方法是使用generator function。您的简单将下一个号码添加到M
系列可以实现为:
def growing_sequence():
M = []
counter = 0
while True:
M.append(counter)
counter += 1
yield M[:]
每次迭代时,这将产生更长的列表 on demand :
>>> gen = growing_sequence()
>>> next(gen)
[0]
>>> next(gen)
[0, 1]
>>> for i, lst in enumerate(gen):
... print i, lst
... if i == 2: break
...
0 [0, 1, 2]
1 [0, 1, 2, 3]
2 [0, 1, 2, 3, 4]
答案 1 :(得分:3)
这将基于Haskell的iterate。
iterate :: (a -> a) -> a -> [a]
iterate f x
会返回f
到x
重复申请的无限列表:
iterate f x == [x, f x, f (f x), ...]
在Python中:
def iterate(f, x):
while True:
yield x
x = f(x)
使用示例:
>>> import itertools.islice
>>> def take(n, iterable):
... return list(islice(iterable, n))
>>> take(4, iterate(lambda x: x + [len(x) + 1], [1]))
[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
要生成有限列表,类型签名(为了清晰起见,再次从Haskell开始)可以是infiniteFinitely :: (a -> Maybe a) -> a -> [a]
。
如果我们在Python中使用list
代替Maybe
:
from itertools import takewhile
def iterateFinitely(f, x):
return map(lambda a: a[0], takewhile(len, iterate(lambda y: f(y[0]), [x])))
使用示例:
>>> list(iterateFinitely(lambda x: [x / 2] if x else [], 20))
[20, 10, 5, 2, 1, 0]
由于以伪造值结束可能很常见,您可能还会添加此功能的一个版本。
def iterateUntilFalsy(f, x):
return iterateFinitely(lambda y: [f(y)] if y else [], x)
使用示例:
>>> list(iterateUntilFalsy(lambda x: x / 2, 20))
[20, 10, 5, 2, 1, 0]
>>> list(iterateUntilFalsy(lambda x: x[1:], [1,2,3,4]))
[[1, 2, 3, 4], [2, 3, 4], [3, 4], [4], []]
答案 2 :(得分:3)
你可以这样做:
M=[1]
L=[M]
for e in range(5):
li=L[-1][:]
li.append(li[-1]+1)
L.append(li)
或更简洁:
for e in range(5):
L.append(L[-1][:]+[L[-1][-1]+1])
答案 3 :(得分:3)
我认为最好的方法是使用generator。这样,您就不必处理list.append
,深层复制列表或任何废话。
def my_generator(max):
for n in range(max+1):
yield list(range(n+1))
然后,你只需要列出 - 如果它:
>>> list(my_generator(5))
[[0], [0,1], [0,1,2], [0,1,2,3], [0,1,2,3,4], [0,1,2,3,4,5]]
如果你想让它成为无限的发电机,这种方法也更灵活。只需切换for
的{{1}}循环。
答案 4 :(得分:2)
试试这个:
M = [1]
L = [M]
for _ in xrange(3):
L += [L[-1] + [L[-1][-1] + 1]]
执行上述代码后,L
将包含[[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
。说明:
for
行说明在设置初始值后我们要执行多少循环,在这种情况下为3
。我使用_
作为迭代变量,因为我们对它的值不感兴趣,我们只想做一定数量的循环现在是有趣的部分;并记住在Python中,列表中的负索引从末尾开始计数,因此-1
的索引指向最后一个元素。
L += …
更新列表,在循环中添加新子列表的次数与循环中指定的次数相同[L[-1] + …]
通过获取最后一个子列表并在末尾添加一个新元素来创建一个新的子列表[L[-1][-1] + 1]
获取最后一个子列表中的前一个元素,向其中添加一个元素并返回一个单元素列表,以便在前一个表达式的末尾连接