2017-05-24 1 views
3

En python 2 lors de l'utilisation d'un OrderedDict j'ai été en mesure d'obtenir les clés dans l'ordre où elles ont été insérées en utilisant simplement la méthode keys qui a renvoyé une liste. En python 3 cependant:OrderedDict en python 3 - comment obtenir les clés dans l'ordre?

rows = OrderedDict() 
rows[0]=[1,2,3] 
rows[1]=[1,2,3] 
image = [rows[k] for k in rows.keys()[:2]] 

Je reçois:

Traceback (most recent call last): 
    File "<input>", line 1, in <module> 
TypeError: 'odict_keys' object is not subscriptable 

Je ne peux certainement faire list(rows)[:2] comme conseillé par exemple here - mais est-ce garanti pour me obtenir les clés de commande? Est-ce la bonne façon?

MISE À JOUR: le python 2 code serait mieux que:

image = [v for v in rows.values()[:2]] 

qui bien sûr souffle toujours avec la même erreur sur python 3

+4

Oui, faire 'list (rows)' est la bonne façon d'obtenir les clés dans l'ordre puisque cela utilise '__iter__' et' __next__' dont l'ordre est garanti. Si vous avez seulement besoin des 2 premières clés, vous pourriez envisager quelque chose comme 'itertools.islice (rows, 2)' au lieu de 'list (rows) [: 2]' ... – mgilson

+0

Merci @mgilson - je ne sais pas ce que je ferais être plus rapide - copier une petite liste ou utiliser le module itertools - peut-être essayer une réponse? :) –

Répondre

1

@mglison est juste. Parce que OrderedDict suit le protocole itérateur, il est garanti yield les clés dans le bon ordre pour list():

Cependant, comme @mglison a également mentionné, itertools.islice() serait mieux et plus efficent que d'utiliser simplement list et subscripting. Après avoir chronométré les deux méthodes plusieurs fois en utilisant le module timeit, la méthode itertools était environ 2x plus rapide. Voici les chiffres exacts:

Après avoir obtenu le temps moyen de courir à la fois list(itertools.islice(rows, 2)) et list(rows.keys())[:2] (avis je casting le résultat de islice() à une liste) plusieurs fois, il semble que cette dernière méthode en utilisant est légèrement plus rapide réelle :

--------------------------------------------------------------- 
| list(itertools.islice(rows, 2)) | 1.5023668839901838 |  
--------------------------------------------------------------- 
| list(rows.keys())[:2]    | 1.495460570215706 |  
--------------------------------------------------------------- 

Cependant, la différence des deux nombres est si petit, je ne voudrais pas faire beaucoup de différence que la méthode utilisée. Choisissez simplement la méthode la plus lisible et la plus compréhensible pour votre cas spécifique.

+0

Si c'est exactement ce que vous avez fait, je ne pense pas que ce soit une comparaison équitable: 'itertools.islice (rows, 2)' par lui-même ne fait pas de liste. Vous auriez besoin de le comparer à 'list (itertools.islice (rows, 2))', et je pense que les deux approches seraient beaucoup plus proches à ce point. – DSM

+0

@DSM Ah, votre bonne capture. Je ne sais pas où était mon cerveau. Je vais recalculer les extraits de code et mettre à jour ma réponse. –

+0

zzzz s'il vous plaît ajouter le code timeit zzzz :) - @ DSM - cependant je suis intéressé par itérer sur les touches dans l'ordre afin que ce peut être une comparaison équitable –