Krish V
Krish V

Reputation: 546

How to group dictionary elements in python3

I have dictionary like the one below, trying to group the dictionary with entry/exit time of the member.

summary = {
    0: {
        'member_id': 10,
        'entry_time': '08:10 PM',
        'entry_device': 'Front',
        'exit_time': None,
        'exit_device': None
    },
    1: {
        'member_id': 8,
        'entry_time': '10:10 PM',
        'entry_device': 'Front',
        'exit_time': None,
        'exit_device': None
    },
    2: {
        'member_id': 10,
        'entry_time': None,
        'entry_device': None,
        'exit_time': '09:05 PM',
        'exit_device': 'Gate'
    },
    3: {
        'member_id': 8,
        'entry_time': None,
        'entry_device': None,
        'exit_time': '11:55 PM',
        'exit_device': 'Gate'
    },
    4: {
        'member_id': 10,
        'entry_time': '11:56 PM',
        'entry_device': 'Front',
        'exit_time': None,
        'exit_device': None
    }
}

And this is my code, just stuck here. Trying to append the member_list for an element in the summary.

summary_data = {}
for i, _ in summary.items():
    summary_data[str(i)] = {}
    member_list = []
    member_list.append(summary_data[i]['member_id'])

Need to group the entry and exit times for the member in a new dictionary

summary = {
    0: {
        'member_id': 10,
        'entry_time': '08:10 PM',
        'entry_device': 'Front',
        'exit_time': '09:05 PM',
        'exit_device': 'Gate'
    },
    1: {
        'member_id': 8,
        'entry_time': '10:10 PM',
        'entry_device': 'Front',
        'exit_time': '11:55 PM',
        'exit_device': 'Gate'
    },
    2: {
        'member_id': 10,
        'entry_time': '11:56 PM',
        'entry_device': 'Front',
        'exit_time': '-',
        'exit_device': '-'
    },
}

Upvotes: 2

Views: 89

Answers (2)

Sociopath
Sociopath

Reputation: 13401

You can use pandas for it.

Firs sort the values by member_id then use shift to fill next exit_time of corresponding entry_time. Use drop_duplicates to drop duplicate rows which has same member_id and exit_time

import pandas as pd
import numpy as np     

df = pd.DataFrame.from_dict(summary, orient='index')

df = df.sort_values(by='member_id')
df0 = df.shift(-1)

df['exit_time'] = np.where(df['exit_time'].isnull(), df0['exit_time'], df['exit_time'])
df['exit_device'] = np.where(df['exit_device'].isnull(), df0['exit_device'], df['exit_device'])
df = df.drop_duplicates(subset=['member_id','exit_time'], keep='first')

# if you want to fill nan with `-` then use below
# df = df.fillna("-")

print(df.to_dict(orient='records'))

Output:

[{'entry_device': 'Front',                                                                                                              
  'entry_time': '10:10 PM',                                                                                                             
  'exit_device': 'Gate',                                                                                                                
  'exit_time': '11:55 PM',                                                                                                              
  'member_id': 8},                                                                                                                      
 {'entry_device': 'Front',                                                                                                              
  'entry_time': '08:10 PM',                                                                                                             
  'exit_device': 'Gate',                                                                                                                
  'exit_time': '09:05 PM',                                                                                                              
  'member_id': 10},                                                                                                                     
 {'entry_device': 'Front',                                                                                                              
  'entry_time': '11:56 PM',                                                                                                             
  'exit_device': nan,                                                                                                                   
  'exit_time': nan,                                                                                                                     
  'member_id': 10}]  

Upvotes: 1

Ralf
Ralf

Reputation: 16505

One option to group all the data by members is to use the member_id as the keys of a dict:

import collections

summary = [ ...the data that you showed in the question... ]
new_summary = collections.defaultdict(
    lambda: {
        'entry': [],
        'exit': [],
    })

for elem in summary.values():
    member_id = elem['member_id']

    if elem['entry_time'] is not None:
        new_summary[member_id]['entry'].append(
            (elem['entry_time'], elem['entry_device']))
    if elem['exit_time'] is not None:
        new_summary[member_id]['exit'].append(
            (elem['exit_time'], elem['exit_device']))

for k, v in new_summary.items():
    print(k, v['entry'])
    print(k, v['exit'])

This gives the following output:

10 [('08:10 PM', 'Front'), ('11:56 PM', 'Front')]
10 [('09:05 PM', 'Gate')]
8 [('10:10 PM', 'Front')]
8 [('11:55 PM', 'Gate')]

Now, if you want to group entries and exits by time then you would need to convert the strings to datetime objects and sort the lists, and then interlace/pair them in an orderly fashion. Just sorting the strings might not give you the desired result because the AM/PM part is at the end of the string.

Upvotes: 0

Related Questions