# How to clone an iterable and recursively replace specific values?

1285 views
4

I'm writing a widget, that allows to specify the arrangement of its parts.

To accomplish this, I'm using the modular principle:
'Building blocks' are used to specify any order.

These 'blocks' are implemented as an enum values, where each value represents an individual component.

``````import enum

# The 'blocks'
class E(enum.Enum):
A = 1
B = 2
C = 3

class Test():
def __init__(self, arrangement):
# The passed 'arrangement' is translated into the real arrangement.
real_arrangement = []

for a in arrangement:
if a == E.A:
real_arrangement.append("a_component")
elif a == E.B:
real_arrangement.append("b_component")
elif a == E.C:
real_arrangement.append("c_component")

print(real_arrangement)

# The user can specify an arrangement...
arrangement = (E.A, E.C, E.B)

# ... and pass it to the constructor.
Test(arrangement)

# 'real_arrangement' = ("a_component", "c_component", "b_component")
``````

Please note, that the placeholders are replaced, but the structure is the same.

However, I also like to give some freedom regarding the properties of the elements. Thus, in addition to the pure enum value, an iterable can be passed, which contains the enum value and further parameters.

``````# the elements are iterables themself.
arrangement = ((10, E.A),
(20, E.C),
(5, E.B))

# real_arrangement = ((10, "a_component"), (20, "c_component"), (5, "b_component"))
``````

Please note, that the structure is the same.

### So I'm basically try to clone an iterable and recursively replace specific values.

Any approach I thought of is quite unreadable.
Is there perhaps already a solution that I can use?

The above code was run with Python 3.5.2.

0

One option can be to check if elements are iterable and use `itertools.chain` if it is (without changing much of your code):

``````import enum
import collections
from itertools import chain

# ...
class Test():
def __init__(self, arrangement):
real_arrangement = []
if all(isinstance(i, collections.Iterable) for i in arrangement):
arrangement = chain.from_iterable(arrangement)

for a in arrangement:
#...

#...
``````

This will make is work for both types of input for `arrangement`.

posted this