Disons que j'ai la liste suivante en python. Il est commandé en premier par Equip, puis par Date:
my_list = [
{'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-01'},
{'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-02'},
{'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-03'},
{'Equip': 'A-1', 'Job': 'Job 2', 'Date': '2018-01-04'},
{'Equip': 'A-1', 'Job': 'Job 2', 'Date': '2018-01-05'},
{'Equip': 'A-2', 'Job': 'Job 1', 'Date': '2018-01-03'},
{'Equip': 'A-2', 'Job': 'Job 3', 'Date': '2018-01-04'},
{'Equip': 'A-2', 'Job': 'Job 3', 'Date': '2018-01-05'}
]
Ce que je veux faire, c'est réduire la liste de chaque jeu où un élément donné du travail de l'équipement ne change pas, et saisir la première et la dernière date à laquelle l'équipement était là. Par exemple, cet exemple simple devrait devenir:
list_by_job = [
{'Equip': 'A-1', 'Job': 'Job 1', 'First': '2018-01-01', 'Last': '2018-01-03'},
{'Equip': 'A-1', 'Job': 'Job 2', 'First': '2018-01-04', 'Last': '2018-01-05'},
{'Equip': 'A-2', 'Job': 'Job 1', 'First': '2018-01-03', 'Last': '2018-01-03'},
{'Equip': 'A-2', 'Job': 'Job 3', 'First': '2018-01-04', 'Last': '2018-01-05'}
]
Quelques points à noter:
A-2
sur Job 1
n'est présent que pour un seul jour. Par conséquent, ses First
et Last
Date devraient être identiques.Pour le point 3, la liste
my_list = [
{'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-01'},
{'Equip': 'A-1', 'Job': 'Job 2', 'Date': '2018-01-02'},
{'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-03'}
]
devrait céder
list_by_job = [
{'Equip': 'A-1', 'Job': 'Job 1', 'First': '2018-01-01', 'Last': '2018-01-01'},
{'Equip': 'A-2', 'Job': 'Job 2', 'First': '2018-01-02', 'Last': '2018-01-02'},
{'Equip': 'A-1', 'Job': 'Job 1', 'First': '2018-01-03', 'Last': '2018-01-03'}
]
Actuellement, je le fais d'une manière simple en boucle/non-Pythonique:
list_by_job = []
last_entry = None
for entry in my_list:
if last_entry is None or last_entry['Equip'] != entry['Equip'] or last_entry['Job'] != entry['Job']:
list_by_job.append({'Equip': entry['Equip'], 'Job': entry['Job'], 'First': entry['Date'], 'Last': entry['Date']})
else:
list_by_job[-1]['Last'] = entry['Date']
last_entry = entry
Existe-t-il une manière plus pythonique de faire cela en utilisant la compréhension de liste de Python, etc.?
Vous pouvez utiliser itertools.groupby
:
import itertools
def _key(d):
return (d['Equip'], d['Job'])
my_list = [{'Date': '2018-01-01', 'Equip': 'A-1', 'Job': 'Job 1'}, {'Date': '2018-01-02', 'Equip': 'A-1', 'Job': 'Job 1'}, {'Date': '2018-01-03', 'Equip': 'A-1', 'Job': 'Job 1'}, {'Date': '2018-01-04', 'Equip': 'A-1', 'Job': 'Job 2'}, {'Date': '2018-01-05', 'Equip': 'A-1', 'Job': 'Job 2'}, {'Date': '2018-01-03', 'Equip': 'A-2', 'Job': 'Job 1'}, {'Date': '2018-01-04', 'Equip': 'A-2', 'Job': 'Job 3'}, {'Date': '2018-01-05', 'Equip': 'A-2', 'Job': 'Job 3'}]
new_data = [[a, list(b)] for a, b in itertools.groupby(my_list, key=_key)]
final_result = [{"Equip":c, 'Job':d, 'First':b[0]['Date'], 'Last':b[-1]['Date']} for [c, d], b in new_data]
Sortie:
[{'Equip': 'A-1', 'Job': 'Job 1', 'Last': '2018-01-03', 'First': '2018-01-01'},
{'Equip': 'A-1', 'Job': 'Job 2', 'Last': '2018-01-05', 'First': '2018-01-04'},
{'Equip': 'A-2', 'Job': 'Job 1', 'Last': '2018-01-03', 'First': '2018-01-03'},
{'Equip': 'A-2', 'Job': 'Job 3', 'Last': '2018-01-05', 'First': '2018-01-04'}]
Modifier:
Utilisation des données comme suggéré dans votre commentaire:
my_list = [{'Date': '2018-01-01', 'Equip': 'A-1', 'Job': 'Job 1'}, {'Date': '2018-01-02', 'Equip': 'A-1', 'Job': 'Job 2'}, {'Date': '2018-01-03', 'Equip': 'A-1', 'Job': 'Job 1'}, {'Date': '2018-01-04', 'Equip': 'A-1', 'Job': 'Job 2'}, {'Date': '2018-01-05', 'Equip': 'A-1', 'Job': 'Job 2'}, {'Date': '2018-01-03', 'Equip': 'A-2', 'Job': 'Job 1'}, {'Date': '2018-01-04', 'Equip': 'A-2', 'Job': 'Job 3'}, {'Date': '2018-01-05', 'Equip': 'A-2', 'Job': 'Job 3'}]
Sortie:
[{'Equip': 'A-1', 'Job': 'Job 1', 'Last': '2018-01-01', 'First': '2018-01-01'},
{'Equip': 'A-1', 'Job': 'Job 2', 'Last': '2018-01-02', 'First': '2018-01-02'},
{'Equip': 'A-1', 'Job': 'Job 1', 'Last': '2018-01-03', 'First': '2018-01-03'},
{'Equip': 'A-1', 'Job': 'Job 2', 'Last': '2018-01-05', 'First': '2018-01-04'},
{'Equip': 'A-2', 'Job': 'Job 1', 'Last': '2018-01-03', 'First': '2018-01-03'},
{'Equip': 'A-2', 'Job': 'Job 3', 'Last': '2018-01-05', 'First': '2018-01-04'}]
Je suggère d'utiliser pandas
pour cela.
itertools.groupby
est cool mais IMO un peu plus difficile à comprendre.
>>> import pandas as pd
>>>
>>> my_list = [
...: {'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-01'},
...: {'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-02'},
...: {'Equip': 'A-1', 'Job': 'Job 1', 'Date': '2018-01-03'},
...: {'Equip': 'A-1', 'Job': 'Job 2', 'Date': '2018-01-04'},
...: {'Equip': 'A-1', 'Job': 'Job 2', 'Date': '2018-01-05'},
...: {'Equip': 'A-2', 'Job': 'Job 1', 'Date': '2018-01-03'},
...: {'Equip': 'A-2', 'Job': 'Job 3', 'Date': '2018-01-04'},
...: {'Equip': 'A-2', 'Job': 'Job 3', 'Date': '2018-01-05'}
...:]
>>>
>>> df = pd.DataFrame(my_list)
>>> df['Date'] = pd.to_datetime(df['Date'])
>>> groups = df.groupby(['Equip', 'Job']).agg({'Date': [min, max]}).reset_index()
>>> groups.columns = ['Equip', 'Job', 'First', 'Last']
>>> groups
>>>
Equip Job First Last
0 A-1 Job 1 2018-01-01 2018-01-03
1 A-1 Job 2 2018-01-04 2018-01-05
2 A-2 Job 1 2018-01-03 2018-01-03
3 A-2 Job 3 2018-01-04 2018-01-05
>>>
>>> groups.to_dict(orient='records')
>>>
[{'Equip': 'A-1',
'First': Timestamp('2018-01-01 00:00:00'),
'Job': 'Job 1',
'Last': Timestamp('2018-01-03 00:00:00')},
{'Equip': 'A-1',
'First': Timestamp('2018-01-04 00:00:00'),
'Job': 'Job 2',
'Last': Timestamp('2018-01-05 00:00:00')},
{'Equip': 'A-2',
'First': Timestamp('2018-01-03 00:00:00'),
'Job': 'Job 1',
'Last': Timestamp('2018-01-03 00:00:00')},
{'Equip': 'A-2',
'First': Timestamp('2018-01-04 00:00:00'),
'Job': 'Job 3',
'Last': Timestamp('2018-01-05 00:00:00')}]
Je suggère de garder les dates comme horodatage.
Vous pouvez utiliser des pandas ici, qui sont une sorte "d'interface de base de données" pour les données:
import pandas as pd
df = pd.DataFrame(my_list)
df2 = df.groupby(['Equip', 'Job']).agg(['min', 'max']).rename(columns={'min': 'First', 'max': 'Last'})
df2.columns = df2.columns.droplevel()
df2 = df2.reset_index()
result = df2.to_dict('records')
pour l'échantillon donné, cela donne:
>>> df2.to_dict('records')
[{'Equip': 'A-1', 'Job': 'Job 1', 'First': '2018-01-01', 'Last': '2018-01-03'},
{'Equip': 'A-1', 'Job': 'Job 2', 'First': '2018-01-04', 'Last': '2018-01-05'},
{'Equip': 'A-2', 'Job': 'Job 1', 'First': '2018-01-03', 'Last': '2018-01-03'},
{'Equip': 'A-2', 'Job': 'Job 3', 'First': '2018-01-04', 'Last': '2018-01-05'}]
Si le format de date est pas '%Y-%m-%d'
, il faut d’abord le convertir avec pd.to_datetime(..)
comme:
import pandas as pd
df = pd.DataFrame(my_list)
df['Date'] = pd.to_datetime(df['Date'])
df2 = df.groupby(['Equip', 'Job']).agg(['min', 'max']).rename(columns={'min': 'First', 'max': 'Last'})
df2.columns = df2.columns.droplevel()
df2 = df2.reset_index()
result = df2.to_dict('records')