大多数Pythonic迭代建立列表的方法?

时间:2014-08-30 23:50:03

标签: python list

我试图用Python做一些使用以下一般过程的东西,我想知道最好的方法是什么。

首先,初始化步骤:

  • 创建项目M.
  • 创建一个列表L并将M添加到L.

其次,循环通过以下内容:

  • 通过修改添加到L的最后一项来创建新项目。
  • 将新项目添加到L。

作为一个简单的例子,假设我想创建一个列表列表,其中第n个列表包含从1到n的数字。我可以使用以下(愚蠢)程序。

  • 最初M是[1],L = [[1]]。
  • 接下来,通过向它添加2来修改[1]以创建新项[1,2],然后将[1,2]添加到L,因此L = [[1],[1,2]]。
  • 接下来,通过添加3来修改[1,2]以创建新项目[1,2,3],然后将[1,2,3]添加到L中,因此L = [[1],[1] ,2],[1,2,3]]。
  • 接下来,通过向其添加4来修改[1,2,3]以创建新项目[1,2,3,4],然后将[1,2,3,4]添加到L,因此L = [ [1],[1,2],[1,2,3],[1,2,3,4]。 等

我尝试了一些东西,但是大多数东西不仅会修改最后添加的项目,还会修改前面步骤中添加到L的项目。对于我感兴趣的特定问题,我确实设法找到一个行为正常的解决方案(至少对于小案例),但它似乎不优雅,我不知道为什么它在其他事情没有时起作用,而且我'我甚至不相信它会像大案一样表现出来。我也不相信我可以调整我的方法来解决类似的问题。我不理解这个问题,因为我在其他编程语言中编写了同样的东西而没有问题。

所以我想知道更有经验的Python程序员将如何处理这项一般任务。

(我省略了我自己的代码部分是因为我是新来的,我还没弄清楚如何在stackoverflow上输入它,但也因为它很长,我不想要帮助解决特定问题,而不是如何处理我上面描述的更一般的过程。)

5 个答案:

答案 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会返回fx重复申请的无限列表:

     

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]获取最后一个子列表中的前一个元素,向其中添加一个元素并返回一个单元素列表,以便在前一个表达式的末尾连接