Reputation: 722
I've written a function that accepts, works and return simple, non-nested tuples.
eg.:
myfun((1,2,3,4)):
... -> logic
return (1,2,3,4) -> the numbers can change, but the shape will be the same
Since the logic works only with mono-dimensional tuples but is conceptually the same for each level of nesting. I was wondering if there's a way to convert a nested tuple like ((1,2,(3,)),(4,))
into the plain (1,2,3,4)
and then convert it back to ((1,2,(3,)),(4,))
.
Basically what I want is to unpack a generic input tuple, work with it, and then pack the results in the same shape of the given one.
Is there a Pythonic way to accomplish such a task?
Probably the unpacking could be solved with recursion, however I'm not sure about the "re-packing" part.
Upvotes: 4
Views: 1259
Reputation: 2576
I submit my version. It uses the same function to flat and reconstruct the list. If flat
is None
it flattens, otherwise it reconstructs by yielding a tuple.
import collections
def restructure(original, flat=None):
for el in original:
if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
if flat:
yield tuple(restructure(el, flat))
else:
yield from restructure(el)
else:
yield next(flat) if flat else el
def gen():
i = 0
while True:
yield i
i += 1
def myfun(iterable):
flat = tuple(restructure(iterable))
# your transformation ..
flat = gen() # assigning infinite number generator for testing
return restructure(iterable, flat=iter(flat))
x = (1, (2, 3), (4, (5, 6)))
print(tuple(y for y in myfun(x))) # (0, (1, 2), (3, (4, 5)))
Upvotes: 1
Reputation: 15249
This should work for the repacking:
x = (1,(2,3),(4,(5,6)))
y = (9,8,7,6,5,4)
def map_shape(x, y, start=0):
if type(x) == tuple:
l = []
for item in x:
mapped, n_item = map_shape(item, y[start:])
start += n_item
l.append(mapped)
return tuple(l), start
else:
return y[start], start+1
map_shape(x,y)[0]
Output:
(9, (8, 7), (6, (5, 4)))
Upvotes: 2
Reputation: 1510
The unpacking is not that hard:
def unpack(parent):
for child in parent:
if type(child) == tuple:
yield from unpack(child)
else:
yield child
for example, can do the trick.
Repacking is a bit trickier. I came up with the following, which works but is not very pythonic, I'm afraid:
def repack(structured, flat):
output = []
global flatlist
flatlist = list(flat)
for child in structured:
if type(child) == tuple:
output.append(repack(child, flatlist))
else:
output.append(flatlist.pop(0))
return tuple(output)
Example usage is:
nested = ((1, 2, (3,)), (4,))
plain = tuple(unpack(nested))
renested = repack(nested, plain)
Hope this helps!
Upvotes: 3