2016-11-24 50 views
0

所以我列表的嵌套字典称为dict1如下:Else子句有两个回路

{"types": [{"name": "Chinese", 
      "sub": 
       [{ 
        "menu": [{"name": "Ya", "cost": 1}, {"name": "Ja", "cost": 2}], 
        "name": "Soups" 
       }, 
       { 
        "menu": [{"name": "Ta", "cost": 3}, {"name": "Ba", "cost": 4}], 
        "name": "Mains" 
       }] 
      }, 
      {"name": "Indian(Mains)", 
      "menu": [{"name": "Sa", "cost": 5}, {"name": "Pa", "cost": 6}] 
      } 
     ] 
} 

我最后需要的是:

{"types": [{"name": "Chinese(Soups)", 
      "menu": [{"name": "Ya", "cost": 1}, {"name": "Ja", "cost": 2}]}, 

      {"name": "Chinese(Mains)", 
      "menu": [{"name": "Ta", "cost": 3}, {"name": "Ba", "cost": 4}]}, 

      {"name": "Indian(Mains)", 
      "menu": [{"name": "Sa", "cost": 5}, {"name": "Pa", "cost": 6}]} 
      ] 
} 

所以在总结,如果内部字典包含密钥,则将其分离为单独的字符串,否则保持原样。对于最有名的给我,我使用列表解析this.This原因是我至今:

dict1['types'] = [{'name': '%s(%s)' % (outer['name'], inner['name']), 
        'menu': inner['menu']} 
        for outer in dict1['types'] 
        if 'sub' in outer 
        for inner in outer['sub']] 

这给了我下面的输出:

{"types": [{"name": "Chinese(Soups)", 
      "menu": [{"name": "Ya", "cost": 1}, {"name": "Ja", "cost": 2}]}, 

      {"name": "Chinese(Mains)", 
      "menu": [{"name": "Ta", "cost": 3}, {"name": "Ba", "cost": 4}]} 
      ] 
} 

很明显,它给我只有2个字符,而不是3,这是显而易见的,因为我没有其他子句。我的问题是,如何在列表理解中使用else子句,并在此场景中使用两个循环?

编辑 正如马亭在评论中提到的,这是不可能的名单理解,我行与实现这一以及通过修改现有的字典

+1

在列表理解循环中'if'只能*过滤*(排除)项目。没有'else'选项,因为包含一个项目是默认的。 –

+0

@Martijn彼得斯...请问,请让我知道什么是最好的方式来完成这一点,而不创建一个新的字典和修改现有的字典? – Amistad

回答

1

在列表理解循环的其他方式,if只允许你过滤迭代的项目,而不是换出更多的循环。因为if充当过滤器,所以没有else作为中的默认操作,其中包括迭代的元素。

你不得不使用表达式在你的内循环挑两个备选方案之一为for循环遍历:

[{'name': '%s(%s)' % (outer['name'], inner['name']), 'menu': inner['menu']} if 'sub' in outer else inner 
for outer in dict1['types'] 
for inner in (outer['sub'] if 'sub' in outer else [outer])] 

所以这种采要么outer['sub']列表或列表[outer]到重复执行inner名称。然后,您可以使用条件表达式来生成新字典,或者仅在outer中没有'sub'密钥的情况下重新使用inner(这实际上是outer)。

当然,你可以简化使用dict.get()

[{'name': '%s(%s)' % (outer['name'], inner['name']), 'menu': inner['menu']} if 'sub' in outer else inner 
for outer in dict1['types'] 
for inner in outer.get('sub', [outer])] 

演示:

>>> dict1 = {"types": [{"name": "Chinese", 
...    "sub": 
...     [{ 
...     "menu": [{"name": "Ya", "cost": 1}, {"name": "Ja", "cost": 2}], 
...     "name": "Soups" 
...     }, 
...     { 
...     "menu": [{"name": "Ta", "cost": 3}, {"name": "Ba", "cost": 4}], 
...     "name": "Mains" 
...     }] 
...   }, 
...   {"name": "Indian(Mains)", 
...    "menu": [{"name": "Sa", "cost": 5}, {"name": "Pa", "cost": 6}] 
...   } 
...   ] 
... } 
>>> [{'name': '%s(%s)' % (outer['name'], inner['name']), 'menu': inner['menu']} if 'sub' in outer else inner 
... for outer in dict1['types'] 
... for inner in outer.get('sub', [outer])] 
[{'name': 'Chinese(Soups)', 'menu': [{'name': 'Ya', 'cost': 1}, {'name': 'Ja', 'cost': 2}]}, {'name': 'Chinese(Mains)', 'menu': [{'name': 'Ta', 'cost': 3}, {'name': 'Ba', 'cost': 4}]}, {'name': 'Indian(Mains)', 'menu': [{'name': 'Sa', 'cost': 5}, {'name': 'Pa', 'cost': 6}]}] 
>>> from pprint import pprint 
>>> pprint(_) 
[{'menu': [{'cost': 1, 'name': 'Ya'}, {'cost': 2, 'name': 'Ja'}], 
    'name': 'Chinese(Soups)'}, 
{'menu': [{'cost': 3, 'name': 'Ta'}, {'cost': 4, 'name': 'Ba'}], 
    'name': 'Chinese(Mains)'}, 
{'menu': [{'cost': 5, 'name': 'Sa'}, {'cost': 6, 'name': 'Pa'}], 
    'name': 'Indian(Mains)'}] 

个人而言,我在这里使用一个发电机的功能,而不是单一的列表理解:

def flattened_menu(types): 
    for entry in types: 
     if 'sub' in entry: 
      # flatten out nested menu entries 
      for subentry in entry['sub']: 
       yield { 
        'name': '{0[name]}({1[name]})'.format(entry, subentry), 
        'menu': subentry['menu']} 
     else: 
      yield entry 

dict1['types'] = list(flattened_menu(dict1['types'])) 
+0

只是为了了解..没有使用列表理解有没有更好的方法? – Amistad

+0

@Amistad:我添加了一个替代方案;不要害怕在这里使用一个更详细的函数,这使得以后很容易找出代码的作用。 –

+0

非常感谢.. – Amistad