2015-01-30 3 views
2

Ok, так что я пытаюсь написать функцию Python, которая превращает первую строку здесь, список вложенных кортежей, во вторую линию, сплющенный словарь:Python преобразовать список вложенных кортежей в Словарь

[('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} 

Небольшое осложнение состоит в том, что внешние кортежи в списке являются членами разных объектов и что аргумент функции представляет собой список этих объектов. Надеюсь, приведенный ниже код объясняет это.

Теперь я на самом деле удалось сколотить решение этой проблемы, но это настолько отвратительное, что я должен спросить, как сделать это в более вещий/менее запутанным образом:

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)) 

Два print statements производят вывод двух строк в верхней части вопроса.

+4

правильный ответ, чтобы исправить вашу структуру данных .... –

+0

'Dict (список (застежка-молния (* ([iter (list (flatten (list (l.sn для l в args))))] * 2)))) 'довольно Pythonic. то же самое с 'flatten = lambda * n: (e для a в n для e in (flatten (* a), если isinstance (a, (кортеж, список)) else (a,)))' и '[l.sn для l в списке]. Но, по общему признанию, уродливый. Как сказал Джоаран, это из-за формата вашей входной структуры. –

+0

Принял ответ от сеншина, который действительно является (очень маленьким) изменением в моей структуре данных. –

ответ

2

Можете изменить определение le так, чтобы self.sn был кортежей там, где есть в lf? Если да, то это легко:

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} 

Кроме того, возможно, рассматривать не используя нижний регистр «L» S так щедро в короткие имена переменных, потому что это медведь и половина для чтения в большинстве шрифтов.

+0

Ах, блестящий. Я действительно могу изменить определение le для этого. Точка взята о нижнем регистре «L» (это было извлечено из большего кода и лишено контекста). –

0

Вы можете легко написать рекурсивный flattener, но это не будет вести себя так, как ожидалось, для двухэлементных кортежей кортежей, например. (('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} 

Вы могли бы быть в состоянии иметь больше успеха, оптимизируйте yield условную НЕМНОГО:

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) 
+0

хороший ответ, хотя он все равно может дать плохие результаты ... вы должны проверить, является ли элемент [0] списком или кортежем –