l = ["a", "b", "c", "d", "e"]
Je veux convertir cette liste en dictionnaire comme:
d = {"a": "b", "c": "d", "e": ""}
Donc, fondamentalement, les événements seront des clés, alors que les chances seront des valeurs. Je sais que je peux le faire de manière "non-Pythonique", telle qu'une boucle for avec des instructions if, mais je crois qu'il devrait exister un moyen plus "Pythonique" pour accomplir cela. Donc, j'apprécie toute aide :)
En utilisant la formule habituelle recette de groupe , vous pouvez effectuer les opérations suivantes:
Python 2:
d = dict(itertools.izip_longest(*[iter(l)] * 2, fillvalue=""))
Python 3:
d = dict(itertools.Zip_longest(*[iter(l)] * 2, fillvalue=""))
Si vous pensez toujours ce que le! Vous ne seriez pas seul, ce n’est en fait pas si compliqué que cela, laissez-moi vous expliquer.
Nous voulons transformer la liste suivante en dictionnaire en utilisant les entrées impaires (en partant de 1) en tant que clés mappées sur leurs entrées paires consécutives.
l = ["a", "b", "c", "d", "e"]
Pour créer un dictionnaire, nous pouvons utiliser la fonction dict
intégrée pour Types de mappage conformément au manuel, les méthodes suivantes sont prises en charge.
dict(one=1, two=2)
dict({'one': 1, 'two': 2})
dict(Zip(('one', 'two'), (1, 2)))
dict([['two', 2], ['one', 1]])
La dernière option suggère que nous fournissions une liste de listes avec 2 valeurs ou (key, value)
tuples, nous voulons donc transformer notre liste séquentielle en:
l = [["a", "b"], ["c", "d"], ["e",]]
Nous sommes également initiés à la fonction Zip
, ne des fonctions intégrées à laquelle le manuel explique:
retourne une liste de tuples, où le i-ème tuple contient le i-ème élément de chacun des arguments
En d’autres termes, si nous pouvons transformer notre liste en deux listes a, c, e
et b, d
, alors Zip
fera le reste.
Slicings que nous voyons utilisé avec Strings et aussi plus loin dans le section List qui utilise principalement le plage ou - notation courte notation mais voici à quoi ressemble la notation coupe longue et ce que nous pouvons accomplir avec étape:
>>> l[::2]
['a', 'c', 'e']
>>> l[1::2]
['b', 'd']
>>> Zip(['a', 'c', 'e'], ['b', 'd'])
[('a', 'b'), ('c', 'd')]
>>> dict(Zip(l[::2], l[1::2]))
{'a': 'b', 'c': 'd'}
Même s'il s'agit du moyen le plus simple de comprendre les mécanismes impliqués, il existe un inconvénient, car les tranches sont chaque fois de nouveaux objets de liste, comme on peut le voir avec cet exemple de clonage:
>>> a = [1, 2, 3]
>>> b = a
>>> b
[1, 2, 3]
>>> b is a
True
>>> b = a[:]
>>> b
[1, 2, 3]
>>> b is a
False
Bien que b ressemble à a, ce sont deux objets distincts maintenant et c'est pourquoi nous préférons utiliser le recette du groupeur .
Bien que le groupeur soit expliqué dans le cadre du module itertools, il fonctionne également parfaitement avec les fonctions de base.
Un sérieux vaudou non? =) Mais en réalité, rien de plus qu'un peu de sucre de syntaxe pour les épices, la recette du mérou est accomplie par l'expression suivante.
*[iter(l)]*2
Ce qui correspond plus ou moins à deux arguments du même itérateur, enveloppés dans une liste, si cela a du sens. Permet de le décomposer pour aider à faire la lumière.
>>> l*2
['a', 'b', 'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e']
>>> [l]*2
[['a', 'b', 'c', 'd', 'e'], ['a', 'b', 'c', 'd', 'e']]
>>> [iter(l)]*2
[<listiterator object at 0x100486450>, <listiterator object at 0x100486450>]
>>> Zip([iter(l)]*2)
[(<listiterator object at 0x1004865d0>,),(<listiterator object at 0x1004865d0>,)]
>>> Zip(*[iter(l)]*2)
[('a', 'b'), ('c', 'd')]
>>> dict(Zip(*[iter(l)]*2))
{'a': 'b', 'c': 'd'}
Comme vous pouvez le constater, les adresses des deux itérateurs restent les mêmes. Nous travaillons donc avec le même itérateur. Zip obtient ensuite une clé, puis une valeur, une clé et une valeur à chaque fois que le même itérateur est utilisé pour accomplir ce que nous avons fait. avec les tranches beaucoup plus productive.
Vous obtiendrez le même résultat avec ce qui suit, qui comporte peut-être un facteur moins important What the?.
>>> it = iter(l)
>>> dict(Zip(it, it))
{'a': 'b', 'c': 'd'}
Qu'en est-il de la clé vide e
si vous avez remarqué qu'elle est absente de tous les exemples, car Zip
choisit le plus court des deux arguments, que devons-nous faire?.
Une solution consiste peut-être à ajouter une valeur vide aux listes de longueurs irrégulières. Vous pouvez également utiliser append
et une instruction if
qui feraient l'affaire, bien que légèrement ennuyeux, n'est-ce pas?
>>> if len(l) % 2:
... l.append("")
>>> l
['a', 'b', 'c', 'd', 'e', '']
>>> dict(Zip(*[iter(l)]*2))
{'a': 'b', 'c': 'd', 'e': ''}
Maintenant, avant de hausser les épaules pour aller taper from itertools import izip_longest
vous serez peut-être surpris de savoir que ce n'est pas nécessaire, nous pouvons accomplir la même chose, encore mieux à mon humble avis, avec les seules fonctions intégrées.
Je préfère utiliser la fonction map () au lieu de izip_longest () qui, non seulement utilise une syntaxe plus courte, ne nécessite pas d'importation, mais peut affecter une valeur vide None
lorsque requis, automagiquement.
>>> l = ["a", "b", "c", "d", "e"]
>>> l
['a', 'b', 'c', 'd', 'e']
>>> dict(map(None, *[iter(l)]*2))
{'a': 'b', 'c': 'd', 'e': None}
En comparant les performances des deux méthodes, comme l'a souligné KursedMetal, il est clair que le module itertools surpasse de loin la fonction de carte sur des volumes importants, comme le montre l'indice comparé à 10 millions d'enregistrements.
$ time python -c 'dict(map(None, *[iter(range(10000000))]*2))'
real 0m3.755s
user 0m2.815s
sys 0m0.869s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(10000000))]*2, fillvalue=None))'
real 0m2.102s
user 0m1.451s
sys 0m0.539s
Cependant, le coût d'importation du module pèse lourdement sur des jeux de données plus petits, la carte renvoyant beaucoup plus rapidement jusqu'à environ 100 000 enregistrements quand ils commencent à arriver tête à tête.
$ time python -c 'dict(map(None, *[iter(range(100))]*2))'
real 0m0.046s
user 0m0.029s
sys 0m0.015s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100))]*2, fillvalue=None))'
real 0m0.067s
user 0m0.042s
sys 0m0.021s
$ time python -c 'dict(map(None, *[iter(range(100000))]*2))'
real 0m0.074s
user 0m0.050s
sys 0m0.022s
$ time python -c 'from itertools import izip_longest; dict(izip_longest(*[iter(range(100000))]*2, fillvalue=None))'
real 0m0.075s
user 0m0.047s
sys 0m0.024s
Ne rien voir! =)
nonJoy!
J'irais pour des récursions:
l = ['a', 'b', 'c', 'd', 'e', ' ']
d = dict([(k, v) for k,v in Zip (l[::2], l[1::2])])
Je ne sais pas si cela vous aiderait ou non, mais cela fonctionne pour moi:
l = ["a", "b", "c", "d", "e"]
outRes = dict((l[i], l[i+1]) if i+1 < len(l) else (l[i], '') for i in xrange(len(l)))