Reputation: 123
Ok, so I am trying to write a Python function that turns the first line here, a list of nested tuples, into the second line, a flattened dictionary:
[('Ka',0.6), ('La', 0.6), (('Ma', 0.7), ('Na', 0.8), ('Oa', 0.9))]
{'La': 0.6, 'Ma': 0.7, 'Ka': 0.6, 'Na': 0.8, 'Oa': 0.9}
A slight complication is that the outer tuples in the list are members of different objects, and that the argument of the function is a list of these objects. Hopefully the code below explains this.
Now I have actually managed to cobble together a solution to this problem, but it is so hideous that I have to ask how to do this in a more pythonic / less obfuscated way:
def theFunction(args):
# Please don't ask me how this works. It just does.
flatten = lambda *n: (e for a in n for e in (flatten(*a) if
isinstance(a, (tuple, list)) else (a,)))
return dict(list(zip(*([iter(list(flatten(list(l.sn for l in args))))]*2))))
class le:
def __init__(self,n):
self.sn = (n,0.6)
class lf:
def __init__(self,n,m,o):
self.sn = (n,0.7), (m,0.8), (o, 0.9)
l1 = le("Ka")
l2 = le("La")
l3 = lf("Ma","Na","Oa")
theList = [l1,l2,l3]
print([l.sn for l in theList])
print(theFunction(theList))
The two print statements produce as output the two lines at the top of the question.
Upvotes: 2
Views: 1180
Reputation: 54213
You can easily write a recursive flattener, but this won't behave as expected for two-element tuples of tuples e.g. (('tuple','one'), ('tuple','two'))
def recurse_flatten(seq):
for el in seq:
if isinstance(el, tuple) and len(el)==2:
yield el
else:
yield from recurse_flatten(el)
>>> dict(recurse_flatten([('Ka',0.6), ('La', 0.6), (('Ma', 0.7), ('Na', 0.8), ('Oa', 0.9))]))
{'Ma': 0.7, 'Na': 0.8, 'La': 0.6, 'Ka': 0.6, 'Oa': 0.9}
You might be able to have more success by refining your yield
conditional a bit:
def recurse_flatten(seq):
for el in seq:
if isinstance(el, tuple) and len(el)==2:
one,two = el
if isinstance(one, str) and isinstance(two,float):
yield el
continue
yield from recurse_flatten(el)
Upvotes: 0
Reputation: 10360
Can you change the definition of le
so that self.sn
is a tuple of tuples there, like it is in lf
? If so, this is easy:
class le:
def __init__(self, n):
self.sn = (n, 0.6),
# ^ make self.sn a tuple of tuples in all cases
class lf:
def __init__(self, n, m, o):
self.sn = (n, 0.7), (m, 0.8), (o, 0.9)
l1 = le("Ka")
l2 = le("La")
l3 = lf("Ma","Na","Oa")
theList = [l1, l2, l3]
result = dict([tup for thing in theList for tup in thing.sn])
# result == {'Na': 0.8, 'Ka': 0.6, 'Ma': 0.7, 'Oa': 0.9, 'La': 0.6}
Also, maybe consider not using lowercase "L"s so liberally in short variable names, because it's a bear and a half to read in most fonts.
Upvotes: 2