0

I've found numerous solutions on how to repeat a List of Lists while flattening the repeated elements, like so:

[[1,2] for x in range(3)]
: [[1, 2], [1, 2], [1, 2]]

However, I actually have a list of objects that need to be repeated in-line in the List, like so:

mylist = [var1, var2, var1, var2, va1, var2]

without the extra inner list, and importantly, var1 should be copied, not referenced, such that changes to mylist[0] will not also change mylist[2] & mylist[4] etc. Other solutions regarding lists only still leave the list elements as “pointers”, meaning editing one element actually alters all the repeats of that element in the list.

Is there a readable one-liner for using multiplication/comprehension to do this while removing the “pointers” in the list?

This is an operation users may have to do often with my class and a for() loop will make construction of their list much less readable. I'm already sad that we can't just use [var1, var2] * 30 without overloading __mult__, which I'm trying to avoid. That would have made their code so readable.


For example, the following use of deepcopy() is not good enough, as the objects are referenced and thus unexpectedly altered

>>> obj1=[1]; obj2=[200]
>>> a=deepcopy( 3*[obj1, obj2] )
>>> a
[[1], [200], [1], [200], [1], [200]]
>>> a[0][0]=50
>>> a
[[50], [200], [50], [200], [50], [200]]

the 50 propagated throughout the list, rather than changing only the first element.

Demis
  • 5,278
  • 4
  • 23
  • 34

2 Answers2

2

You need

import copy
[copy.copy(y) for x in range(3) for y in [var1, var2]]

Or shallow copy is not enough

[copy.deepcopy(y) for x in range(3) for y in [var1, var2]]
gzc
  • 8,180
  • 8
  • 42
  • 62
1

I'm not quite sure what behavior you're looking for. Depending on what you want, one of these two options might be right:

In [0]: from itertools import chain

In [1]: from copy import deepcopy

In [2]: [deepcopy(x) for x in 3*[var1, var2]]
Out[2]: [[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]]

In [3]: list( chain( *(3*[var1, var2]) ) )
Out[3]: [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
Stuart Berg
  • 17,026
  • 12
  • 67
  • 99
  • Thanks, I would have thought `deepcopy( 3*[var1, var2] )` would work, but it seems they're still referenced to each other - changes to `mylist[0]` are also changing `mylist[2]` & `mylist[4]`. (sorry can't paste example code here - won't accept newlines) – Demis Mar 18 '17 at 16:44
  • Added code to question, showing why this didnt work as I need it. Will try your second method later today. Thanks! – Demis Mar 18 '17 at 16:57
  • 1
    Whoa, crap, you're totally right. Thanks for pointing that out -- I hadn't thought hard enough about how deepcopy works. It will duplicate a set of objects, including internal references they make to eachother, such that no copied objects in the new set refer to the old set. But for every "internal" reference in the old set, an identical "internal" reference exists in the copied set. (Updated the answer with a correction.) – Stuart Berg Mar 18 '17 at 17:07