简体   繁体   中英

flattened dictionary into nested dictionary of dictionaries of lists

So I can't seem to figure out how to effectively implement this. I'm looking to nest a flattened dictionary into dictionary of dictionaries of lists, based on specific keys as inputs. Trying so desperately to learn

Given that my data looks like this:

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

I'd want to return something like this if I give it parameters like reorder(data,['location','team','player']) for an example

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

You can use the setdefault function to automatically build the nesting levels as you go through the data:

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"]})

output:

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

[EDIT] Generalizing the approach

If you have to do this kind of thing often and on different types of dictionaries or hierarchies, you could generalize it in a function:

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

You would then give the function a list of dictionaries followed by the names of the keys you want to nest:

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

If you want to group the same data in a different way, you just need to change the order of the field names:

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

From there you can have some fun with the function and improve it to aggregate the data at the lowest nesting level:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM