How to group the same values into same key?

Question:

I have an assignment to do this things without import any helpful function, could you guys help me?
Thanks!

data = [
    ['num','e1','e2','e3'],
    ['2002','p','r','i'],
    ['2002','k','r','i'],
    ['2001','k','r','e'],
    ['2004','p','a','p'],
    ['2004','p','s','f']
]

newlist = [
    {'num': '2001', 'e1': 'k', 'e2': 'r', 'e3': 'e'},
    {'num': '2002', 'e1': 'p', 'e2': 'r', 'e3': 'i'},
    {'num': '2002', 'e1': 'k', 'e2': 'r', 'e3': 'i'},
    {'num': '2004', 'e1': 'p', 'e2': 'a', 'e3': 'p'},
    {'num': '2004', 'e1': 'p', 'e2': 's', 'e3': 'f'}
]

How can I convert newlist into this by num is main key and next key is e1

{
    '2001':{
        'k':[{'num': '2001', 'e1': 'k', 'e2': 'r', 'e3': 'e'}]
    },
    '2002':{
        'k':[{'num': '2002', 'e1': 'k', 'e2': 'r', 'e3': 'i'}],
        'p':[{'num': '2002', 'e1': 'p', 'e2': 'r', 'e3': 'i'}]
    },
    '2004':{
        'p':[{'num': '2004', 'e1': 'p', 'e2': 'a', 'e3': 'p'}, {'num': '2004', 'e1': 'p', 'e2': 's', 'e3': 'f'}]
    }
}

2001 and 2002 have only k and k have only one data so it will be the only one member of k
you will see its form { num: {e1: [ {'num':..., 'e1': ..., 'e2': ... }, ... ], ...}, ... }

Asked By: user21308739

||

Answers:

One way would be to loop through the input list (data or newlist) and use .setdefault and .append to fill up the nested dictionary or lists.


To get the nested dictionary from data:

result, kList, vData = {}, data[0], data[1:]
for r in vData:
    k_outer, k_inner = r[:2]
    dict_inner = result.setdefault(k_outer, {})
    list_inner = dict_inner.setdefault(k_inner, [])
    list_inner.append(dict(zip(kList, r)))

To get the nested dictionary from newlist:

# newlist = [dict(zip(data[0],r)) for r in data[1:]] # <-- get newlist from data

result, k_outer_key, k_inner_key = {}, 'num', 'e1'
for r in newlist:
    k_outer, k_inner = r.get(k_outer_key), r.get(k_inner_key)
    dict_inner = result.setdefault(k_outer, {})
    list_inner = dict_inner.setdefault(k_inner, [])
    list_inner.append(r)



You can also use dictionary comprehension to create a nested dictionary containing empty lists and then loop through data or newlist and add each dictionary in the input list to whichever list it belongs to in the nested dictionary.

(You could filter the input list for each nested key right away with list comprehension when you’re defining the nested dictionary, but doing it in a separate loop actually reduces the total number of times you loop through the input data.)


To get the nested dictionary from data, you can use

kList, vData = data[0], data[1:]

result = {k_outer: {
    k_inner: [] for k, k_inner, *_ in vData if k==k_outer
} for k_outer in {k1 for k1, *_ in vData}}

for r in vData: result[r[0]][r[1]].append(dict(zip(kList,r)))

## OR 
''' ## [SLIGHTLY LESS EFFICIENT]
kList, vData = data[0], data[1:]
result = {k_outer: {
    k_inner: [dict(zip(kList,x)) for x in vData if x[0]==k_outer and x[1]==k_inner] 
    for k, k_inner, *_ in vData if k==k_outer
} for k_outer in {k1 for k1, *_ in vData}}
''' 

To get the nested dictionary from newlist, you can use

k_outer, k_inner = 'num', 'e1'

result = {k: {
    d.get(k_inner): [] for d in newlist if k==d.get(k_outer)
} for k in {r.get(k_outer) for r in newlist}}

for r in newlist: result[r.get(k_outer)][r.get(k_inner)].append(r)

## OR 
''' ## [SLIGHTLY LESS EFFICIENT]
k_outer, k_inner = 'num', 'e1'
result = {k: {d.get(k_inner): [
    x for x in newlist if x.get(k_outer)==k and x.get(k_inner)==d.get(k_inner)
] for d in newlist if k==d.get(k_outer)} for k in {r.get(k_outer) for r in newlist}}
'''



Whichever approach is taken, result should look like

{
  '2004': {
    'p': [{'num': '2004', 'e1': 'p', 'e2': 'a', 'e3': 'p'}, {'num': '2004', 'e1': 'p', 'e2': 's', 'e3': 'f'}]
  },
  '2002': {
    'p': [{'num': '2002', 'e1': 'p', 'e2': 'r', 'e3': 'i'}],
    'k': [{'num': '2002', 'e1': 'k', 'e2': 'r', 'e3': 'i'}]
  },
  '2001': {
    'k': [{'num': '2001', 'e1': 'k', 'e2': 'r', 'e3': 'e'}]
  }
}
Answered By: Driftr95