如何解压缩列表理解中的列表

问题描述 投票:2回答:4

我有一个字典列表,每个字典可以嵌套一个字典列表,如:

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']

但是这会导致错误!我可以使用for,如果没有列表理解,也可以这样做(并且已经做到了),但是我想知道使用列表(或元组拆包)和列表理解来做到这一点的正确语法是什么?

python list-comprehension iterable-unpacking
4个回答
0
投票
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)

0
投票

这里是一个相当通用的解决方案,它将以dict和list的任何组合递归。这将返回一个简单的名称值列表。

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
投票

您几乎要在这里

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
投票

我能做的最接近的是在必要时提供“伪”第二级,然后忽略它:

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,它们都将运行,但是可以有条件地生成第二个循环的“主题”(最初我使用lambda进行了此操作,但显然带括号的表达式就足够了。)

您的尝试有一个错误,for next in iter应该是for next in iter['next-level'](而且iter()是内置函数,所以我将其重命名为item)。而且,如果尝试了一些不太雄心勃勃的操作,您将遇到一条明确的错误消息:无法理解的可重复拆包

© www.soinside.com 2019 - 2024. All rights reserved.