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

时间:2022-03-16 22:08:06

I was trying to do something in Python that uses the following general procedure, and I want to know what the best way to approch this is.

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

First, an initialization step:

首先,初始化步骤:

  • Create an item M.
  • 创建一个项目M.

  • Create a list L and add M to L.
  • 创建一个列表L并将M添加到L.

Second, loop through the following:

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

  • Create a new item by modifying the last item added to L.
  • 通过修改添加到L的最后一项来创建新项目。

  • Add the new item to L.
  • 将新项添加到L.

As a simple example, say I want to create a list of lists where the nth list contains the numbers from 1 to n. I could use the following (silly) procedure.

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

  • Initially M is [1] and L=[[1]].
  • 最初M是[1]而L = [[1]]。

  • Next, modify [1] by adding 2 to it to create the new item [1,2], then add [1,2] to L so L=[[1],[1,2]].
  • 接下来,通过向它添加2来修改[1]以创建新项目[1,2],然后将[1,2]添加到L,因此L = [[1],[1,2]]。

  • Next, modify [1,2] by adding 3 to it to create the new item [1,2,3], then add [1,2,3] to L so L=[[1],[1,2],[1,2,3]].
  • 接下来,通过向它添加3来修改[1,2]以创建新项目[1,2,3],然后将[1,2,3]添加到L中,因此L = [[1],[1,2] ,[1,2,3]]。

  • Next, modify [1,2,3] by adding 4 to it to create the new item [1,2,3,4], then add [1,2,3,4] to L so L=[[1],[1,2],[1,2,3],[1,2,3,4]]. etc.
  • 接下来,通过向它添加4来修改[1,2,3]以创建新项[1,2,3,4],然后将[1,2,3,4]添加到L中,因此L = [[1] ,[1,2],[1,2,3],[1,2,3,4]。等等

I tried a few things, but most of them would modify not just the last item added but also items added to L in previous steps. For the particular problem I was interested in, I did manage to find a solution that behaves properly (at least for small cases), but it seems inelegant, I’m not sure why it works when other things didn’t, and I’m not even confident that it would still behave as desired for large cases. I’m also not confident that I could adapt my approach to similar problems. It's not a case of me not understanding the problem, since I've coded the same thing in other programming languages without issues.

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

So I’m wondering how more experienced Python programmers would handle this general task.

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

(I’m omitting my own code in part because I’m new here and I haven’t figured out how to enter it on *, but also because it's long-ish and I don’t want help with the particular problem, but rather with how to handle the more general procedure I described above.)

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

5 个解决方案

#1


10  

When adding a list object M to another list, you are only adding a reference; continuing to manipulate the list M means you will see those changes reflected through the other reference(s) too:

将列表对象M添加到另一个列表时,只添加引用;继续操纵列表M意味着您将看到通过其他参考反映的那些更改:

>>> M = []
>>> resultlist = []
>>> resultlist.append(M)
>>> M is resultlist[0]
True
>>> M.append(1)
>>> resultlist[0]
[1]
>>> M
[1]

Note that M is resultlist[0] is True; it is the same object.

注意,M是resultlist [0]为True;它是同一个对象。

You'd add a copy of M instead:

你要添加M的副本:

resultlist.append(M[:])

The whole slice here ([:] means to slice from start to end) creates a new list with a shallow copy of the contents of M.

这里的整个切片([:]表示从头到尾切片)创建一个新的列表,其中包含M的内容的浅表副本。

The generic way to build produce a series L from a continuously altered starting point M is to use a generator function. Your simple add the next number to M series could be implemented as:

从连续改变的起点M生成L系列的通用方法是使用生成器函数。您的简单添加M系列的下一个数字可以实现为:

def growing_sequence():
    M = []
    counter = 0
    while True:
        M.append(counter)
        counter += 1
        yield M[:]

This will yield ever longer lists each time you iterate, 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]

#2


3  

You can do:

你可以做:

M=[1]
L=[M]

for e in range(5):
    li=L[-1][:]
    li.append(li[-1]+1)
    L.append(li)

Or more tersely:

或者更简洁:

for e in range(5):
    L.append(L[-1][:]+[L[-1][-1]+1])

#3


3  

I think that the best way to do this is with a generator. That way, you don't have to deal with list.append, deep-copying lists or any of that nonsense.

我认为最好的方法是使用发电机。这样,您就不必处理list.append,深层复制列表或任何废话。

def my_generator(max):
  for n in range(max+1):
    yield list(range(n+1))

Then, you just have to list-ify it:

然后,你只需要列出 - 如果它:

>>> 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]]

This approach is also more flexible if you wanted to make it an infinite generator. Simply switch the for loop for a while true.

如果你想让它成为无限的发电机,这种方法也更灵活。只需将for循环切换一段时间即可。

#4


3  

This will be based on iterate from Haskell.

这将基于Haskell的迭代。

iterate :: (a -> a) -> a -> [a]

iterate ::(a - > a) - > a - > [a]

iterate f x returns an infinite list of repeated applications of f to x:

iterate f x返回f到x的重复应用的无限列表:

iterate f x == [x, f x, f (f x), ...]

迭代f x == [x,f x,f(f x),...]

In Python:

def iterate(f, x):
    while True:
        yield x
        x = f(x)

Example usage:

>>> 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]]

To produce a finite list, the type signature (again starting in Haskell just for clarity) could be infiniteFinitely :: (a -> Maybe a) -> a -> [a].

为了生成有限列表,类型签名(再次从Haskell开始只是为了清晰起见)可以是无限的::(a - >可能是a) - > a - > [a]。

If we were to use list in place of Maybe in Python:

如果我们在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])))

Example usage:

>>> list(iterateFinitely(lambda x: [x / 2] if x else [], 20))
[20, 10, 5, 2, 1, 0]

Since ending with a falsy value is probably pretty common, you might also add a version of this function that does that.

由于以伪造值结束可能很常见,您可能还会添加此功能的一个版本。

def iterateUntilFalsy(f, x):
    return iterateFinitely(lambda y: [f(y)] if y else [], x)

Example usage:

>>> 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], []]

#5


2  

Try this:

M = [1]
L = [M]  
for _ in xrange(3):
    L += [L[-1] + [L[-1][-1] + 1]]

After the above code is executed, L will contain [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]. Explanation:

执行上述代码后,L将包含[[1],[1,2],[1,2,3],[1,2,3,4]]。说明:

  • The first two lines simply seed the iteration with initial values
  • 前两行简单地使用初始值对迭代进行种子处理

  • The for line states how many loops we want to perform after the initial value has been set, 3 in this case. I'm using _ as the iteration variable because we're not interested in its value, we just want to do a certain number of loops
  • for行说明在设置初始值后我们要执行多少循环,在这种情况下为3。我使用_作为迭代变量,因为我们对它的值不感兴趣,我们只想做一定数量的循环

Now for the interesting part; and remember that in Python a negative index in a list starts counting from the end, so an index of -1 points to the last element.

现在是有趣的部分;并记住在Python中,列表中的负索引从末尾开始计数,因此索引-1指向最后一个元素。

  • This: L += … updates the list, appending a new sublist at the end as many times as specified in the loop
  • 这:L + = ...更新列表,在循环中指定的次数最多添加一个新的子列表

  • This: [L[-1] + …] creates a new sublist by taking the last sublist and adding a new element at the end
  • 这个:[L [-1] + ...]通过获取最后一个子列表并在末尾添加一个新元素来创建一个新的子列表

  • And finally this: [L[-1][-1] + 1] obtains the previous last element in the last sublist, adds one to it and returns a single-element list to be concatenated at the end of the previous expression
  • 最后这个:[L [-1] [ - 1] + 1]获取最后一个子列表中的前一个最后一个元素,向它添加一个元素并返回一个单元素列表,以便在前一个表达式的末尾连接

#1


10  

When adding a list object M to another list, you are only adding a reference; continuing to manipulate the list M means you will see those changes reflected through the other reference(s) too:

将列表对象M添加到另一个列表时,只添加引用;继续操纵列表M意味着您将看到通过其他参考反映的那些更改:

>>> M = []
>>> resultlist = []
>>> resultlist.append(M)
>>> M is resultlist[0]
True
>>> M.append(1)
>>> resultlist[0]
[1]
>>> M
[1]

Note that M is resultlist[0] is True; it is the same object.

注意,M是resultlist [0]为True;它是同一个对象。

You'd add a copy of M instead:

你要添加M的副本:

resultlist.append(M[:])

The whole slice here ([:] means to slice from start to end) creates a new list with a shallow copy of the contents of M.

这里的整个切片([:]表示从头到尾切片)创建一个新的列表,其中包含M的内容的浅表副本。

The generic way to build produce a series L from a continuously altered starting point M is to use a generator function. Your simple add the next number to M series could be implemented as:

从连续改变的起点M生成L系列的通用方法是使用生成器函数。您的简单添加M系列的下一个数字可以实现为:

def growing_sequence():
    M = []
    counter = 0
    while True:
        M.append(counter)
        counter += 1
        yield M[:]

This will yield ever longer lists each time you iterate, 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]

#2


3  

You can do:

你可以做:

M=[1]
L=[M]

for e in range(5):
    li=L[-1][:]
    li.append(li[-1]+1)
    L.append(li)

Or more tersely:

或者更简洁:

for e in range(5):
    L.append(L[-1][:]+[L[-1][-1]+1])

#3


3  

I think that the best way to do this is with a generator. That way, you don't have to deal with list.append, deep-copying lists or any of that nonsense.

我认为最好的方法是使用发电机。这样,您就不必处理list.append,深层复制列表或任何废话。

def my_generator(max):
  for n in range(max+1):
    yield list(range(n+1))

Then, you just have to list-ify it:

然后,你只需要列出 - 如果它:

>>> 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]]

This approach is also more flexible if you wanted to make it an infinite generator. Simply switch the for loop for a while true.

如果你想让它成为无限的发电机,这种方法也更灵活。只需将for循环切换一段时间即可。

#4


3  

This will be based on iterate from Haskell.

这将基于Haskell的迭代。

iterate :: (a -> a) -> a -> [a]

iterate ::(a - > a) - > a - > [a]

iterate f x returns an infinite list of repeated applications of f to x:

iterate f x返回f到x的重复应用的无限列表:

iterate f x == [x, f x, f (f x), ...]

迭代f x == [x,f x,f(f x),...]

In Python:

def iterate(f, x):
    while True:
        yield x
        x = f(x)

Example usage:

>>> 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]]

To produce a finite list, the type signature (again starting in Haskell just for clarity) could be infiniteFinitely :: (a -> Maybe a) -> a -> [a].

为了生成有限列表,类型签名(再次从Haskell开始只是为了清晰起见)可以是无限的::(a - >可能是a) - > a - > [a]。

If we were to use list in place of Maybe in Python:

如果我们在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])))

Example usage:

>>> list(iterateFinitely(lambda x: [x / 2] if x else [], 20))
[20, 10, 5, 2, 1, 0]

Since ending with a falsy value is probably pretty common, you might also add a version of this function that does that.

由于以伪造值结束可能很常见,您可能还会添加此功能的一个版本。

def iterateUntilFalsy(f, x):
    return iterateFinitely(lambda y: [f(y)] if y else [], x)

Example usage:

>>> 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], []]

#5


2  

Try this:

M = [1]
L = [M]  
for _ in xrange(3):
    L += [L[-1] + [L[-1][-1] + 1]]

After the above code is executed, L will contain [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]. Explanation:

执行上述代码后,L将包含[[1],[1,2],[1,2,3],[1,2,3,4]]。说明:

  • The first two lines simply seed the iteration with initial values
  • 前两行简单地使用初始值对迭代进行种子处理

  • The for line states how many loops we want to perform after the initial value has been set, 3 in this case. I'm using _ as the iteration variable because we're not interested in its value, we just want to do a certain number of loops
  • for行说明在设置初始值后我们要执行多少循环,在这种情况下为3。我使用_作为迭代变量,因为我们对它的值不感兴趣,我们只想做一定数量的循环

Now for the interesting part; and remember that in Python a negative index in a list starts counting from the end, so an index of -1 points to the last element.

现在是有趣的部分;并记住在Python中,列表中的负索引从末尾开始计数,因此索引-1指向最后一个元素。

  • This: L += … updates the list, appending a new sublist at the end as many times as specified in the loop
  • 这:L + = ...更新列表,在循环中指定的次数最多添加一个新的子列表

  • This: [L[-1] + …] creates a new sublist by taking the last sublist and adding a new element at the end
  • 这个:[L [-1] + ...]通过获取最后一个子列表并在末尾添加一个新元素来创建一个新的子列表

  • And finally this: [L[-1][-1] + 1] obtains the previous last element in the last sublist, adds one to it and returns a single-element list to be concatenated at the end of the previous expression
  • 最后这个:[L [-1] [ - 1] + 1]获取最后一个子列表中的前一个最后一个元素,向它添加一个元素并返回一个单元素列表,以便在前一个表达式的末尾连接