2017-08-09 7 views
0

J'ai une liste de listes list1 = [['colour','red'],['colour','blue],['shape','rect'],['shape','square']]python: liste des listes à dict ordonnée et par groupe premier élément

ce qui est le meilleur moyen de faire un OrderedDict sur list1?

{colour:['red','blue'],shape:['rect','square']} 

Jusqu'à présent, je suis en mesure de cartographier à travers list1 et extraire des éléments uniques dans l'indice 0 de chaque liste intérieure et le retourner comme liste2.

Je pourrais mapper par list1 et list2 et si élément de maching trouvé alors prendre l'élément à l'index 1 de chaque liste interne de list1 mais je ne suis pas sûr que ce soit approche/approche rapide.

toute aide s'il vous plaît?

Répondre

0

Deux approches, en fonction de vos entrées:

Option 1: Si, comme dans votre exemple, toutes les clés assorties sont consécutives (vous voyez toujours tous ensemble colours), vous pouvez utiliser itertools.groupby les regrouper:

from collections import OrderedDict 
from itertools import groupby 
from operator import itemgetter 

list1 = [['colour','red'],['colour','blue],['shape','rect'],['shape','square']] 
dict1 = OrderedDict((k, [v for _, v in grp]) for k, grp in groupby(list1, itemgetter(0))) 

Ceci est, au moins en théorie, l'approche la plus rapide, car il écrit chaque clé dans le dict exactement une fois sans les regarder à plusieurs reprises chaque fois qu'une touche est vu, mais elle repose sur l'entrée étant commandée par la clé .

Option 2: Utilisez la __missing__ méthode spéciale pour faire un OrderedDict avec le même comportement sur la recherche une clé manquante comme defaultdict(list) (malheureusement, les deux types sont incompatibles, de sorte que vous ne pouvez pas faire une classe qui hérite à la fois et appeler un jour), puis écrire une boucle explicite pour le remplir:

from collections import OrderedDict 

class OrderedMultidict(OrderedDict): 
    __slots__ =() # Avoid overhead of per-instance __dict__ 
    def __missing__(self, key): 
     # Missing keys are seamlessly initialized to an empty list 
     self[key] = retval = [] 
     return retval 

utiliser ensuite pour accumuler les résultats:

dict1 = OrderedMultidict() 
for k, v in list1: 
    dict1[k].append(v) 

Cette approche supprime la dépendance de commande de l'option 1, en échange pour ajouter des recherches répétées de chaque clé (bien que seule la première recherche invoque le code de niveau Python dans __missing__; après cela, si OrderedDict est au niveau C comme dans le code Python 3 moderne, les recherches resteront également au niveau C). Cela dit, alors que les recherches répétées sont théoriquement un peu moins bonnes que d'écrire chaque clé une seule fois, en pratique, je pense que cette solution sera plus rapide sur CPython moderne (où OrderedDict est un C intégré); sur Python 2 et plus ancien Python 3, où il est implémenté en Python (alors que groupby est toujours au niveau C), groupby est plus susceptible de gagner, mais lorsque les deux types sont accélérés en C, groupby a en fait un surcoût supplémentaire qui peut le faire perdre.