уплощенный словарь во вложенный словарь словарей списков - PullRequest
1 голос
/ 29 февраля 2020

Так что я не могу понять, как эффективно реализовать это. Я ищу, чтобы вставить плоский словарь в словарь словарей списков, основываясь на указанных c ключах в качестве входных данных. Так отчаянно пытаясь выучить

Учитывая, что мои данные выглядят так:

data= [
  {
    "player": "Kevin Durant",
    "team": "Thunder",
    "location": "Oklahoma City",
    "points": 15

  },
  {
    "player": "Jeremy Lin",
    "team": "Lakers",
    "location": "Los Angeles",
    "points": 22
  },
  {
    "player": "Kobe Bryant",
    "team": "Lakers",
    "location": "Los Angeles",
    "points": 51
  },
  {
    "player": "Blake Griffin",
    "team": "Clippers",
    "location": "Los Angeles",
    "points": 26
  }
]

Я бы хотел вернуть что-то вроде этого, если я дам ему такие параметры, как переупорядочить (data, ['location ',' team ',' player ']) для примера

result={
  "Los Angeles": {
    "Clippers": {
      "Blake Griffin": [
        {
          "points": 26
        }
      ]
    },
    "Lakers": {
      "Kobe Bryant": [
        {
          "points": 51
        }
      ],
      "Jeremy Lin": [
        {
          "points": 22
        }
      ]
    }
  },
  "Oklahoma City": {
    "Thunder": {
      "Kevin Durant": [
        {
          "points": 15
        }
      ]
    }
  }, 
}

1 Ответ

3 голосов
/ 29 февраля 2020

Вы можете использовать функцию setdefault для автоматического построения уровней вложенности при вводе данных go:

data= [
  {
    "player": "Kevin Durant",
    "team": "Thunder",
    "location": "Oklahoma City",
    "points": 15

  },
  {
    "player": "Jeremy Lin",
    "team": "Lakers",
    "location": "Los Angeles",
    "points": 22
  },
  {
    "player": "Kobe Bryant",
    "team": "Lakers",
    "location": "Los Angeles",
    "points": 51
  },
  {
    "player": "Blake Griffin",
    "team": "Clippers",
    "location": "Los Angeles",
    "points": 26
  }
]

nested = dict()
for d in data:
    nested.setdefault(d["location"],dict()) \
          .setdefault(d["team"],    dict()) \
          .setdefault(d["player"],  list()) \
          .append({"points":d["points"]})

вывод:

print(nested)

{  'Oklahoma City': 
    {  
       'Thunder': 
           {  'Kevin Durant': [{'points': 15}] }
    }, 
    'Los Angeles': 
    { 
       'Lakers': 
           {  
              'Jeremy Lin': [{'points': 22}], 
              'Kobe Bryant': [{'points': 51}]
           }, 
       'Clippers': 
           {  'Blake Griffin': [{'points': 26}] }
     }
  }

[ПРАВКА] Обобщение подхода

Если вам приходится делать такие вещи часто и в разных типах словарей или иерархий, вы можете обобщить это в функции:

def dictNesting(data,*levels):
    result = dict()
    for d in data:
        r = result
        for level in levels[:-1]:
            r = r.setdefault(d[level],dict())
        r = r.setdefault(d[levels[-1]],list())
        r.append({k:v for k,v in d.items() if k not in levels})
    return result

Затем вы должны дать функции список словарей, за которыми следуют имена ключей, которые вы хотите вложить:

byLocation = dictNesting(data,"location","team")

{  'Oklahoma City':
       {  'Thunder': [
              {'player': 'Kevin Durant', 'points': 15}]
       },
   'Los Angeles':
       {'Lakers': [
              {'player': 'Jeremy Lin', 'points': 22},
              {'player': 'Kobe Bryant', 'points': 51}],
        'Clippers': [
              {'player': 'Blake Griffin', 'points': 26}]
       }
}

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

byPlayer = dictNesting(data,"player","location","team")


{  'Kevin Durant':
       {  'Oklahoma City':
              {  'Thunder': [{'points': 15}] }
       },
   'Jeremy Lin':
       {  'Los Angeles':
              {'Lakers': [{'points': 22}]}
       },
   'Kobe Bryant':
       {  'Los Angeles':
              {'Lakers': [{'points': 51}]}
       },
   'Blake Griffin':
       {  'Los Angeles':
              {'Clippers': [{'points': 26}]}
       }
}

Оттуда вы можете позабавиться с функцией и улучшить ее, чтобы агрегировать данные на самом низком уровне вложенности:

def dictNesting(data,*levels,aggregate=False):
    result = dict()
    for d in data:
        r = result
        for level in levels[:-1]:
            r = r.setdefault(d[level],dict())
        r = r.setdefault(d[levels[-1]],[list,dict][aggregate]())
        content = ( (k,v) for k,v in d.items() if k not in levels)
        if aggregate:
            for k,v in content: r.setdefault(k,list()).append(v)
        else:
            r.append(dict(content))
    return result

output:

byCity = dictNesting(data,"location","team",aggregate=True)

{  'Oklahoma City':
        {'Thunder':
             {'player': ['Kevin Durant'], 'points': [15]}},
   'Los Angeles':
        {'Lakers':
             {'player': ['Jeremy Lin', 'Kobe Bryant'], 'points': [22, 51]},
         'Clippers':
             {'player': ['Blake Griffin'], 'points': [26]}
        }
}

lakersPlayers = byCity["Los Angeles"]["Lakers"]["player"] 
# ['Jeremy Lin', 'Kobe Bryant']

lakersPoints  = sum(byCity["Los Angeles"]["Lakers"]["points"]) 
# 73
...