web-dev-qa-db-fra.com

python convertir une liste en dictionnaire

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 :)

70
Shaokan

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=""))
45
Sven Marnach

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.

Comment transformer une liste en dictionnaire à l'aide de fonctions intégrées uniquement

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"]

dict ()

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.

notation de tranche

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 .

recette de mérou

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.

Zip pour le plus court

>>> 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.

carte pour le plus long

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!

136
nickl-

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])])
17
Giorgio Gilestro

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)))
2
Artsiom Rudzenka