简体   繁体   中英

Creating a list of mutable items repeated N times

I have a list containing a set of x mutable items. I would like to create another list where the set of x mutable items is repeated n times. However, the items must be references to unique objects rather than simply references to the original objects.

For example, let a = [[1],[2],[3]] . Suppose I would like the numbers inside to be repeated n=3 times, ie [[0],[2],[3],[1],[2],[3],[1],[2],[3]] .

I can do this easily by using a * 3 . The problem is that if I change a[0][0] = 0 , then I will get a == [[0],[2],[3],[0],[2],[3],[0],[2],[3]] , which is not desirable because I would like to change only the first element. Is there any other way to achieve this?

itertools has a method for this called repeat . Just pair it with chain .

from itertools import repeat, chain

a = [1,2,3]

b = list(chain(*repeat(a, 3)))

>>> b
[1,2,3,1,2,3,1,2,3]

Just do:

n = [sub_a.copy() for sub_a in a] * 3

You need copy() to avoid the problem.

a = [[1],[2],[3]]

n = [sub_a.copy() for sub_a in a] * 3

a[0] = [-1]
a[2][0] = -1

print (n)

Output:

[[1], [2], [3], [1], [2], [3], [1], [2], [3]]

I just figured out I can do this through:

from copy import deepcopy
a = [[1],[2],[3]]
n = 3
b = [deepcopy(val) for _ in range(n) for val in a]

Now if I set b[0][0] = 0 , I will get b == [[0],[2],[3],[1],[2],[3],[1],[2],[3]] .

a = [1,2,3]
a = a*3  
a[0] =0
print(a)

To get new instances of mutable objects, you can map the object type's copy() method to the multiplied list:

a  = [{1},{2},{3}]
b  = [*map(set.copy,a*3)]

a[0].add(7)
b[0].add(8)
b[3].add(9)
print(a) # [{1, 7}, {2}, {3}]
print(b) # [{8, 1}, {2}, {3}, {1, 9}, {2}, {3}, {1}, {2}, {3}]

If you don't know the type of the items, or if they have different types, you can do it in a list comprehension:

b = [ i.copy() for i in a*3 ]

If not all of the items are mutable, you can do it like this:

b = [type(i)(i) for i in a*3]

If some can be None...

b = [i if i is None else type(i)(i) for i in a*3]

You can also use deepcopy which covers all these cases including objects that contain nested objects...

from copy import deepcopy
b  = [*map(deepcopy,a*3)]

Very simply, you need to make copies of a , rather than repeating references to the original, mutable object. If you need just one level of copy, you can do it like this, noting that it's a shallow copy (see second output).

a = [[1, 1], [2], [3, 3, 3]]
b = a[:] * 3
b[0] = "change"
print(b)
b[2][1] = "deep"
print(b)

Output:

['change', [2], [3, 3, 3], [1, 1], [2], [3, 3, 3], [1, 1], [2], [3, 3, 3]]
['change', [2], [3, 'deep', 3], [1, 1], [2], [3, 'deep', 3], [1, 1], [2], [3, 'deep', 3]]

See how only the first level is given a new reference. When you try to change a deeper element, you see that the nested lists are still the same object. To fix that problem, use a deep copy for each element of b :

import copy

a = [[1, 1], [2], [3, 3, 3]]
b = [copy.deepcopy(a) for _ in range(3)]
b[0] = "change"
print(b)
b[2][1] = "deep"
print(b)

Output:

['change', [[1, 1], [2], [3, 3, 3]], [[1, 1], [2], [3, 3, 3]]]
['change', [[1, 1], [2], [3, 3, 3]], [[1, 1], 'deep', [3, 3, 3]]]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM