如何在列表理解中解压列表
how can unpack a list in list comprehension
我有一个字典列表,每个字典都可以有一个嵌套的字典列表:
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 和 if 来做到这一点(并且已经做到了)但是我想知道使用列表(或元组解包)和列表理解来做到这一点的正确语法是什么?
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)
这里是你想要的近
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']
这是一个相当通用的解决方案,它将在任何类型的字典和列表组合中递归。这将 return 名称值的平面列表。
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'))
这将 return:
['foo', 'bar', 'next-level-foo', 'next-level-bar']
我能做的最接近的是在必要时提供 "fake" 第二级,然后忽略它:
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,它们都会 运行,但是第二个循环的 "subject" 可以有条件地生成(最初我是用 lambda 做的,但显然是括号表情就够了)。
你的尝试有一个错误,for next in iter
应该是 for next in iter['next-level']
(另外,iter()
是一个内置函数,所以我将其重命名为 item
).
如果您尝试一些不那么雄心勃勃的事情,您会遇到一条明确的错误消息:iterable unpacking cannot be used in comprehension.
我有一个字典列表,每个字典都可以有一个嵌套的字典列表:
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 和 if 来做到这一点(并且已经做到了)但是我想知道使用列表(或元组解包)和列表理解来做到这一点的正确语法是什么?
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)
这里是你想要的近
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']
这是一个相当通用的解决方案,它将在任何类型的字典和列表组合中递归。这将 return 名称值的平面列表。
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'))
这将 return:
['foo', 'bar', 'next-level-foo', 'next-level-bar']
我能做的最接近的是在必要时提供 "fake" 第二级,然后忽略它:
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,它们都会 运行,但是第二个循环的 "subject" 可以有条件地生成(最初我是用 lambda 做的,但显然是括号表情就够了)。
你的尝试有一个错误,for next in iter
应该是 for next in iter['next-level']
(另外,iter()
是一个内置函数,所以我将其重命名为 item
).
如果您尝试一些不那么雄心勃勃的事情,您会遇到一条明确的错误消息:iterable unpacking cannot be used in comprehension.