I want to create a series of lists, all of varying lengths. Each list will contain the same element e
, repeated n
times (where n
= length of the list).
How do I create the lists, without using a list comprehension [e for number in xrange(n)]
for each list?
This question is related to
python
list-comprehension
multiplication
replicate
As others have pointed out, using the * operator for a mutable object duplicates references, so if you change one you change them all. If you want to create independent instances of a mutable object, your xrange syntax is the most Pythonic way to do this. If you are bothered by having a named variable that is never used, you can use the anonymous underscore variable.
[e for _ in xrange(n)]
>>> [5] * 4
[5, 5, 5, 5]
Be careful when the item being repeated is a list. The list will not be cloned: all the elements will refer to the same list!
>>> x=[5]
>>> y=[x] * 4
>>> y
[[5], [5], [5], [5]]
>>> y[0][0] = 6
>>> y
[[6], [6], [6], [6]]
Create List of Single Item Repeated n Times in Python
Depending on your use-case, you want to use different techniques with different semantics.
For immutable items, like None, bools, ints, floats, strings, tuples, or frozensets, you can do it like this:
[e] * 4
Note that this is usually only used with immutable items (strings, tuples, frozensets, ) in the list, because they all point to the same item in the same place in memory. I use this frequently when I have to build a table with a schema of all strings, so that I don't have to give a highly redundant one to one mapping.
schema = ['string'] * len(columns)
Multiplying a list gives us the same elements over and over. The need for this is rare:
[iter(iterable)] * 4
This is sometimes used to map an iterable into a list of lists:
>>> iterable = range(12)
>>> a_list = [iter(iterable)] * 4
>>> [[next(l) for l in a_list] for i in range(3)]
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]
We can see that a_list
contains the same range iterator four times:
>>> a_list
[<range_iterator object at 0x7fde73a5da20>, <range_iterator object at 0x7fde73a5da20>, <range_iterator object at 0x7fde73a5da20>, <range_iterator object at 0x7fde73a5da20>]
I've used Python for a long time now, and I have seen very few use-cases where I would do the above with mutable objects.
Instead, to get, say, a mutable empty list, set, or dict, you should do something like this:
list_of_lists = [[] for _ in columns]
The underscore is simply a throwaway variable name in this context.
If you only have the number, that would be:
list_of_lists = [[] for _ in range(4)]
The _
is not really special, but your coding environment style checker will probably complain if you don't intend to use the variable and use any other name.
Beware doing this with mutable objects, when you change one of them, they all change because they're all the same object:
foo = [[]] * 4
foo[0].append('x')
foo now returns:
[['x'], ['x'], ['x'], ['x']]
But with immutable objects, you can make it work because you change the reference, not the object:
>>> l = [0] * 4
>>> l[0] += 1
>>> l
[1, 0, 0, 0]
>>> l = [frozenset()] * 4
>>> l[0] |= set('abc')
>>> l
[frozenset(['a', 'c', 'b']), frozenset([]), frozenset([]), frozenset([])]
But again, mutable objects are no good for this, because in-place operations change the object, not the reference:
l = [set()] * 4
>>> l[0] |= set('abc')
>>> l
[set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b']), set(['a', 'c', 'b'])]
[e] * n
should work
Itertools has a function just for that:
import itertools
it = itertools.repeat(e,n)
Of course itertools
gives you a iterator instead of a list. [e] * n
gives you a list, but, depending on what you will do with those sequences, the itertools
variant can be much more efficient.
Source: Stackoverflow.com