How to create a list or tuple of empty lists in Python?

Question:

I need to incrementally fill a list or a tuple of lists. Something that looks like this:

result = []
firstTime = True
for i in range(x):
    for j in someListOfElements:
        if firstTime:
            result.append([f(j)])
        else:
            result[i].append(j)

In order to make it less verbose an more elegant, I thought I will preallocate a list of empty lists

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

The preallocation part isn’t obvious to me. When I do result = [[]] * x, I receive a list of x references to the same list, so that the output of the following

result[0].append(10)
print result

is:

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

I can use a loop (result = [[] for i in range(x)]), but I wonder whether a “loopless” solution exists.

Is the only way to get what I’m looking for

Asked By: Boris Gorelik

||

Answers:

Why not keep it simple by just appending the list in appropriate loop

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']]
Answered By: pyfunc

Please include runnable sample code, so we can run the code ourself to quickly see exactly what it is you want to do. It looks like you just want this:

result = []
for i in range(x):
    data = []
    for j in someListOfElements:
        data.append(j)
    # or data = [j for j in someListOfElements]
    result.append(data)
Answered By: Glenn Maynard

There’s not really a way to create such a list without a loop of some sort. There are multiple ways of hiding the loop, though, just like [[]] * x hides the loop. There’s the list comprehension, which “hides” the loop in an expression (bit it’s thankfully still obvious.) There’s also map(list, [[]]*x) which has two hidden loops (the one in [[]] * x and the one in map that creates a copy of each list using list().)

There’s also the possibility of not creating the list of lists beforehand. The other answers already cover the simple approach, but if that somehow doesn’t fit your needs there are other ways. For example, you could make a function that append an empty list to the result list as necessary, and call that:

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)

Or you could use a collections.defaultdict(list) instead of a list:

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

That has the benefit of using an already existing type, which is less work, but it does mean you now have a dict (indexed by integers) instead of a list, which may or may not be what you want. Or you could make a class that behaves almost like a list but appends new lists to itself instead of raising IndexError, such as:

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)
Answered By: Thomas Wouters

You could write a quick generator function. This would have uses other than this particular case so I’ll generalize it a little. Dig this:

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

Then to make a list of lists,

result = list(create(10))

to make a list of empty dicts,

result = list(create(20, dict))

and (for the sake of completeness) to make a list of empty Foos,

result = list(create(30, Foo))

Of course, you could also make a tuple of any of the above. It wouldn’t be too hard to extend it to allow arguments to constructor either. I would probably have it accept a function which accepted an index and returned the arguments to be passed to the constructor.

One last thought is that, because the only requirement that we are placing on constructor is that it be a callable, you could even pass it anything that returns what you want in your list. A bound method that pulls results out of a database query for instance. It’s quite a useful little three lines of code.

Answered By: aaronasterling
result = [list(someListOfElements) for _ in xrange(x)]

This will make x distinct lists, each with a copy of someListOfElements list (each item in that list is by reference, but the list its in is a copy).

If it makes more sense, consider using copy.deepcopy(someListOfElements)

Generators and list comprehensions and things are considered quite pythonic.

Answered By: Will
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.