Extraire des objets uniques d'une liste de mappages
-
06-07-2019 - |
Question
C’est un problème intéressant qui cherche la solution la plus pythonique. Supposons que j'ai une liste de mappages {'id': id, 'url': url}
. Certains éléments id
de la liste sont en double et je souhaite créer une nouvelle liste en supprimant tous les doublons. Je suis venu avec la fonction suivante:
def unique_mapping(map):
d = {}
for res in map:
d[res['id']] = res['url']
return [{'id': id, 'url': d[id]} for id in d]
Je suppose que c'est assez efficace. Mais existe-t-il un "plus pythonique"? façon ? Ou peut-être un moyen plus efficace?
La solution
Votre exemple peut être légèrement réécrit pour construire le premier dictionnaire à l'aide d'une expression génératrice et supprimer la nécessité de construire d'autres mappages. Il suffit de réutiliser les anciens:
def unique_mapping(mappings):
return dict((m['id'], m) for m in mappings).values()
Même si cela est sorti comme une ligne, je pense toujours que c'est assez lisible.
Il y a deux choses que vous devez garder à l'esprit lorsque vous utilisez votre solution d'origine et la mienne:
- les articles ne seront pas toujours renvoyés dans le même ordre qu'ils étaient à l'origine
- la dernière entrée écrasera les entrées précédentes avec le même identifiant
Si cela ne vous dérange pas, je suggère la solution ci-dessus. Dans les autres cas, cette fonction préserve l’ordre et traite les identifiants rencontrés en premier avec la priorité:
def unique_mapping(mappings):
addedIds = set()
for m in mappings:
mId = m['id']
if mId not in addedIds:
addedIds.add(mId)
yield m
Vous devrez peut-être l'appeler avec la liste (unique_mappings (mappings))
si vous avez besoin d'une liste et non d'un générateur.
Autres conseils
Il y a plusieurs choses que vous pourriez améliorer.
-
Vous effectuez deux boucles, une sur le dict d'origine, puis à nouveau sur le résultat. Vous pouvez créer vos résultats en une étape à la place.
-
Vous pouvez changer pour utiliser un générateur, pour éviter de construire la liste complète au début. (Utilisez list (unique_mapping (items)) pour convertir en une liste complète si vous en avez besoin)
-
Il n'est pas nécessaire de stocker la valeur lors de la vérification des doublons, vous pouvez utiliser un ensemble.
-
Vous recréez un dictionnaire pour chaque élément plutôt que de renvoyer l'original. Cela peut en fait être nécessaire (par exemple, vous les modifiez et vous ne voulez pas toucher à l'original), mais sinon, il est plus efficace d'utiliser les dictionnaires déjà créés.
Voici une implémentation:
def unique_mapping(items):
s = set()
for res in items:
if res['id'] not in s:
yield res
s.add(res['id'])
Je pense que cela peut encore être simplifié. Les dictionnaires ne tolèrent pas les clés en double. Faites votre liste de mappages dans un dictionnaire de mappages. Cela supprimera les doublons.
>>> someListOfDicts= [
{'url': 'http://a', 'id': 'a'},
{'url': 'http://b', 'id': 'b'},
{'url': 'http://c', 'id': 'a'}]
>>> dict( [(x['id'],x) for x in someListOfDicts ] ).values()
[{'url': 'http://c', 'id': 'a'}, {'url': 'http://b', 'id': 'b'}]