如何在Python中创建一个空列表或元组的列表?

41

我需要逐步填充一个列表或元组的列表。类似于这样的东西:

result = []
firstTime = True
for i in range(x):
    for j in someListOfElements:
        if firstTime:
            result.append([f(j)])
        else:
            result[i].append(j)
为了使其更简洁优雅,我打算预分配一个空列表的列表。
result = createListOfEmptyLists(x)
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)

对我来说,预分配的部分不是很清楚。当我执行result = [[]] * x时,我得到了一个包含x个指向同一列表的引用的列表,因此以下操作的输出结果为:

result[0].append(10)
print result

是:

[[10], [10], [10], [10], [10], [10], [10], [10], [10], [10]]

我可以使用循环(result = [[] for i in range(x)]),但我想知道是否存在“无循环”的解决方案。

是不是只有通过循环才能得到我想要的结果?


可能有更好的方法来完成所有这些,但仅凭这段代码很难确定。 - Ignacio Vazquez-Abrams
我可以问一下,列表推导式有什么问题吗?我认为列表乘法并不更优雅或更快(尽管在乘以列表时没有实例化,因此可能更快)。 - AkiRoss
对于一个空列表的列表,可以使用 [ [ [] for c in range(cols) ] for r in range(rows) ] - Tony
5个回答

53
result = [list(someListOfElements) for _ in xrange(x)]

这将创建x个不同的列表,每个列表都有someListOfElements列表的副本(其中该列表中的每个项目都是通过引用传递的,但它所在的列表是一个副本)。

如果更合理,请考虑使用copy.deepcopy(someListOfElements)

生成器和列表推导式等被认为是相当“Pythonic”的东西。


+1:列表推导式不是唯一的解决方案,只是最具有Python风格和我敢说最正确的解决方案。 - Kimvais
5
要创建含有 n 个空列表的列表,请执行 result = [[] for _ in xrange(n)] - gsamaras
1
对于Python3,result = [someListOfElements for _ in range(desired_length)] 可以使用。 - stephenb
@stephenb 这是有效的Python代码,但它并没有做同样的事情。它创建了一个列表,其中每个元素都指向someListOfElements,而不是它们的副本。 - Will
对于@gsamaras提供的解决方案,如果在Python 3中使用,请使用:result = [[] for _ in range(n)],因为xrange已被弃用并且不起作用。 - salvu

7

如果没有循环,就没有办法创建这样的列表。虽然有多种隐藏循环的方法,就像[[]] * x会隐藏循环一样。还有列表生成式,它将循环“隐藏”在表达式中(但仍然很明显)。也可以使用map(list, [[]]*x),其中有两个隐藏的循环(一个在[[]] * x中,另一个在map中,每个列表都是使用list()创建的复制品)。

还有一种可能性是事先不创建列表。其他答案已经涵盖了简单的方法,但如果那些方法不适合您的需要,还有其他方法。例如,您可以编写一个函数,在需要时将空列表附加到result列表中,并调用该函数:

def append(L, idx, item):
    while len(L) <= idx:
        L.append([])
    L[idx].append(item)

for i in range(x):
    for j in someListOfElements:
        append(result, i, j)

或者你可以使用 collections.defaultdict(list) 代替列表:

import collections
result = collections.defaultdict(list)
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)

这样做的好处是使用了已经存在的类型,减少了工作量,但这意味着你现在拥有一个字典(由整数索引),而不是一个列表,这可能是你想要的,也可能不是。或者你可以创建一个类,它的行为几乎像一个列表,但是将新的列表追加到自身而不是引发IndexError,例如:

import UserList
class defaultlist(UserList.UserList):
    def __getitem__(self, idx):
        while len(self) <= idx:
            self.append([])
        return UserList.UserList.__getitem__(self, idx)

result = defaultlist()
for i in range(x):
    for j in someListOfElements:
        result[i].append(j)

1
请注意,[[]] * count 不会创建一个空列表的列表。它创建了一个对同一个空列表的引用列表。向其中一个列表添加条目会将其添加到所有列表中。 - Jeroen

5

你可以编写一个快速的生成器函数。这个函数不仅在当前情况下有用,所以我会稍微概括一下它的用途。看看这个:

def create(n, constructor=list):
    for _ in xrange(n):
        yield constructor()

然后是如何制作列表的步骤:
result = list(create(10))

创建一个空字典列表。
result = list(create(20, dict))

为了完整起见,并列出空的Foos列表。

result = list(create(30, Foo))

当然,您也可以将上述任何内容制作成元组。扩展以允许构造函数参数也不太困难。我可能会让它接受一个函数,该函数接受索引并返回要传递给构造函数的参数。
最后一点是,因为我们对constructor唯一的要求是它可调用,您甚至可以传递任何返回您想要的列表的内容。例如,从数据库查询中提取结果的绑定方法。这是非常有用的三行代码。

4
为什么不在适当的循环中简单地追加列表?
result = []
for i in range(x):
    result.append([])
    for j in someListOfElements:
        result[i].append(j)

[Edit: Adding example]

>>> someListOfElements = ['a', 'b', 'c']
>>> x = 3
>>> result = []
>>> for i in range(x):
...     result.append([])
...     for j in someListOfElements:
...         result[i].append(j)
... 
>>> 
>>> result
[['a', 'b', 'c'], ['a', 'b', 'c'], ['a', 'b', 'c']]

list([]) 有点多余。 - Thomas Wouters

0
请提供可运行的示例代码,这样我们就可以自己运行代码,快速了解您想要做什么。看起来您只是想要这个:
result = []
for i in range(x):
    data = []
    for j in someListOfElements:
        data.append(j)
    # or data = [j for j in someListOfElements]
    result.append(data)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接