web-dev-qa-db-fra.com

Moyen le plus rapide d'obtenir le premier élément de `OrderedDict` en Python 3

Quel est le moyen le plus rapide d’obtenir le premier élément de OrderedDict en Python 3?

Mon meilleur:

list(ordered_dict.items())[0]

Assez long et moche.

Je peux penser à: 

next(iter(ordered_dict.items()))       # Fixed, thanks Ashwini

Mais ce n'est pas très auto-descriptif. 

De meilleures suggestions?

30
Ram Rachum

Pratiques de programmation pour la lisibilité 

En général, si vous pensez que le code n'est pas auto-descriptif, la solution habituelle consiste à le factoriser en une fonction bien nommée:

def first(s):
    '''Return the first element from an ordered collection
       or an arbitrary element from an unordered collection.
       Raise StopIteration if the collection is empty.
    '''
    return next(iter(s))

Avec cette fonction helper , le code suivant devient très lisible:

>>> extension = {'xml', 'html', 'css', 'php', 'xhmtl'}
>>> one_extension = first(extension)

Modèles pour extraire une valeur unique de la collection 

Les méthodes habituelles pour obtenir un élément à partir d'un set, dict, OrderedDict, d'un générateur ou d'une autre collection non indexable sont les suivantes:

for value in some_collection:
    break

et:

value = next(iter(some_collection))

Ce dernier est agréable car la fonction next () vous permet de spécifier une valeur par défaut si la collection est vide ou vous pouvez choisir de la laisser déclencher une exception. La fonction next () indique également explicitement qu'elle demande l'élément suivant.

Approche alternative 

Si vous avez réellement besoin d'indexation et de découpage et d'autres comportements de séquence (tels que l'indexation de plusieurs éléments), il est simple de convertir une liste avec list(some_collection) ou d'utiliser [itertools.islice()][2]:

s = list(some_collection)
print(s[0], s[1])

s = list(islice(n, some_collection))
print(s)
29
Raymond Hettinger

Utilisez popitem(last=False), mais gardez à l’esprit que cela supprime l’entrée du dictionnaire, c’est-à-dire qu’elle est destructive.

from collections import OrderedDict
o = OrderedDict()
o['first'] = 123
o['second'] = 234
o['third'] = 345

first_item = o.popitem(last=False)
>>> ('first', 123)

Pour plus de détails, consultez le manuel sur collections . Cela fonctionne aussi avec Python 2.x.

7
ralien

Sous-classer et ajouter une méthode à OrderedDict serait la réponse aux problèmes de clarté:

>>> o = ExtOrderedDict(('a',1), ('b', 2))
>>> o.first_item()
('a', 1)

L'implémentation de ExtOrderedDict:

class ExtOrderedDict(OrderedDict):
    def first_item(self):
        return next(iter(self.items()))
1
Bryce Guinta

Premier enregistrement :

[key for key, value in ordered_dict][0]

Dernier enregistrement :

[key for key, value in ordered_dict][-1]
0
galaga4

La solution recommandée next(iter(s)) fonctionne dans le cas spécifique où vous souhaitez extraire la valeur first d'une valeur itérable. Si votre itérable est de longueur connue, vous pouvez généraliser pour extraire la valeur n th:

def get_nth_item(it, n=0):
    if n < 0:
        n += len(it)
    for index, item in enumerate(it):
        if index == n:
            return item
    raise IndexError(f'Iterable index {n} out of range')

C'est un moyen clair de clarifier l'intention, en prenant en charge les index négatifs et qui gèrent les erreurs lorsqu'un index incorrect est fourni. Exemple d'utilisation avec OrderedDict:

from collections import OrderedDict

od = OrderedDict([(1, 'a'), (2, 'b'), (3, 'c')])

get_nth_item(od.items(), n=0)   # (1, 'a')
get_nth_item(od.items(), n=-1)  # (3, 'c')
get_nth_item(od.items(), n=3)   # IndexError: Iterable index 3 out of range
0
jpp

Un code lisible laisse le OrderedDict inchangé et ne génère pas inutilement une liste potentiellement longue juste pour obtenir le premier élément:

for item in ordered_dict.items():
    return item

Si command_dict est vide, aucun ne sera retourné implicitement.

Une version alternative à utiliser dans une portion de code:

for first in ordered_dict.items():
    break  # Leave the name 'first' bound to the first item
else:
    raise IndexError("Empty ordered dict")

Le code Python 2.x correspondant au premier exemple ci-dessus devrait utiliser iteritems () à la place:

for item in ordered_dict.iteritems():
    return item
0
YitzikC