2016-11-24 51 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