как распаковать список в понимании списка - PullRequest
2 голосов
/ 30 октября 2019

У меня есть список диктов, каждый из которых может иметь список вложенных диктов, например:

mydictlist = [{'name':'foo'}, {'name':'bar','next-level':[{'name':'next-level-foo'}, {'name':'next-level-bar'}] } ]

Я пытаюсь сгладить какой-то атрибут типа имени в понимании списка следующим образом:

flattened = [ *['{}_{}'.format(iter['name'],next['name']) for next in iter] if 'next-level' in iter else '{}'.format(iter['name']) for iter in mydictlist]

чтобы получить что-то вроде:

['foo', 'bar_next-level-foo', 'bar_next-level-bar']

, но это приводит к ошибке !. Я могу сделать это для и если без понимания списка (и сделал это), но я хочу знать, каков правильный синтаксис для выполнения этого со списком (или распаковкой кортежей) и пониманием списка?

Ответы [ 4 ]

0 голосов
/ 30 октября 2019

Самое близкое, что я могу сделать, - это предоставить «фальшивый» второй уровень при необходимости и игнорировать его впоследствии:

mydictlist = [{'name':'foo'}, {'name':'bar','next-level':[{'name':'next-level-foo'}, {'name':'next-level-bar'}] } ]

flattened = [ '{}_{}'.format(item['name'],next['name']) if next['name'] else item['name'] for item in mydictlist for next in (item['next-level'] if 'next-level' in item else  [{'name':None}]) ]

Вывод:

['foo', 'bar_next-level-foo', 'bar_next-level-bar']

Кажется, нет способа условного цикла в понимании списка. Поэтому, если есть два for -s, они оба будут выполняться, но «субъект» второго цикла может быть сгенерирован условно (изначально я делал это с помощью лямбды, но, видимо, выражения в скобках вполне достаточно).

В вашей попытке произошла ошибка, for next in iter должно было быть for next in iter['next-level'] (также iter() - встроенная функция, поэтому я переименовал ее в item).
И если вы что-то пробовалименее амбициозный, вы бы столкнулись с явным сообщением об ошибке: повторяемая распаковка не может быть использована в понимании .

0 голосов
/ 30 октября 2019

Вот вы хотите почти

result = [x['name'] if "next-level" not in x else [ j['name'] for j in x['next-level']] for x in mydictlist ]
print(result)
# output: ['foo', ['next-level-foo', 'next-level-bar']]
result2 = []
def flettern_list(lst):
    for s in lst:
        if isinstance(s, str):
            result2.append(s)
        elif isinstance(s, list):
            flettern_list(s)
flettern_list(result)
print(result2) #output: ['foo', 'next-level-foo', 'next-level-bar']
0 голосов
/ 30 октября 2019

Вот довольно общее решение, которое можно использовать при любом сочетании слов и списков. Это вернет плоский список значений имени.

def get_leafs_as_list(obj, key):
    l = []
    if isinstance(obj, list):
        for v in obj:
            l.extend(get_leafs_as_list(v, key))
    elif isinstance(obj, dict):
        for k, v in obj.items():
            if k == key:
                l.append(v)
            else:
                l.extend(get_leafs_as_list(v, key))
    return l

mydictlist = [{'name':'foo'}, {'name':'bar','next-level':[{'name':'next-level-foo'}, {'name':'next-level-bar'}] } ]

print(get_leafs_as_list(mydictlist, 'name'))

это вернет:

['foo', 'bar', 'next-level-foo', 'next-level-bar']
0 голосов
/ 30 октября 2019
mydictlist = [{'name':'foo'}, {'name':'bar','next-level':[{'name':'next-level-foo'}, {'name':'next-level-bar'}] } ]

def flatten(currlist, prefix = None, delimiter = "_"):
    l = []
    for x in currlist:
        print (l)
        if "next-level" in x:
            if prefix:
                prefix = delimiter.join([prefix, x["name"]])
            else:
                prefix = x["name"]
            c = flatten(currlist=x["next-level"], prefix=prefix, delimiter=delimiter)
            l.extend(c)
        else:
            if not prefix:
                item = x["name"]
            else:
                item = delimiter.join([prefix, x["name"]])
            l.append(item)
    return l

flatten(currlist=mydictlist)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...