web-dev-qa-db-fra.com

Trier le dictionnaire dans la liste

Il y a déjà beaucoup de questions sur le tri des dictionnaires mais je ne trouve pas la bonne réponse à ma question.

J'ai le dictionnaire v:

v = {3:4.0, 1:-2.0, 10:3.5, 0:1.0}

Nous devons transformer le dictionnaire v en une liste triée.

lijst(v) = [1.0, -2.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.5]

J'ai essayé de travailler avec ce code:

def lijst(x):
    return sorted(x.items(), key=lambda x: x[1])

Voici la liste que je reçois:

lijst(v) = [(1, -2.0), (0, 1.0), (10, 3.5), (3, 4.0)]

Est-ce que quelqu'un sait comment convertir cela en une liste de valeurs triées dans l'ordre de leur clé, les valeurs manquantes étant complétées avec zéro?

15
itseva

Utilisez simplement itertools.chain.from_iterable pour aplatir votre résultat (la liste des n-uplets):

>>> import itertools

>>> list(itertools.chain.from_iterable([(1, -2.0), (0, 1.0), (10, 3.5), (3, 4.0)]))
[1, -2.0, 0, 1.0, 10, 3.5, 3, 4.0]

Au cas où je comprendrais mal votre demande initiale et que le dictionnaire représente un "vecteur fragmenté" (où les clés sont les indices), vous pouvez simplement remplir une liste contenant uniquement des zéros:

>>> res = [0.0]*(max(v)+1)       # create a dummy list containing only zeros
>>> for idx, val in v.items():   # populate the requested indices
...     res[idx] = val 
>>> res
[1.0, -2.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.5]

Ou, si vous avez NumPy, vous pouvez également éviter la boucle for-:

>>> import numpy as np

>>> arr = np.zeros(max(v)+1)
>>> arr[list(v.keys())] = list(v.values())
>>> arr
array([ 1. , -2. ,  0. ,  4. ,  0. ,  0. ,  0. ,  0. ,  0. ,  0. ,  3.5])

La dernière approche repose sur le fait que même si l'ordre de keys et values est arbitraire, ils correspondent néanmoins directement tant qu'il n'y a pas de modification du dictionnaire:

Les clés et les valeurs sont itérées dans un ordre arbitraire non aléatoire, varient selon les implémentations Python et dépendent de l'historique des insertions et des suppressions dans le dictionnaire. Si les vues clés, valeurs et éléments sont réitérées sans modifications intermédiaires du dictionnaire, l'ordre des éléments correspondra directement.

Source 4.10.1. Objets vue dictionnaire

11
MSeifert

Vous pouvez essayer ceci en utilisant chain à partir de itertools:

from itertools import chain

v = {3:4.0, 1:-2.0, 10:3.5, 0:1.0}

final_output = list(chain(*sorted(v.items(), key=lambda x: x[1])))

Sortie:

[1, -2.0, 0, 1.0, 10, 3.5, 3, 4.0]
6
Ajax1234

Une façon de concaténer les paires (clé, valeur) consiste à utiliser sum() avec une valeur initiale:

>>> sum(sorted(v.items(), key=lambda x:x[1]), ())
(1, -2.0, 0, 1.0, 10, 3.5, 3, 4.0)

Cela retourne un tuple. Passez-le à list() si vous avez vraiment, vraiment besoin d’une liste.

P.S. Comme @MSeifert l’a souligné à juste titre dans les commentaires, la complexité temporelle en a certainement (O ** n) alors que list(chain(...)) est probablement amortie linéairement.

5
NPE

Une autre option consiste à utiliser la syntaxe yield fromintroduite dans Python 3.3 :

>>> lst = [(1, -2.0), (0, 1.0), (10, 3.5), (3, 4.0)]
>>> list([(yield from tup) for tup in lst])
[1, -2.0, 0, 1.0, 10, 3.5, 3, 4.0]
>>> 

Caveat: Notez que l'utilisation de yield from de cette façon dans la compréhension de la liste peut ne pas être une "syntaxe non logique" et que certaines (y compris Guido) considèrent que c'est un bug .

4
Christian Dean

Vous pouvez utiliser la compréhension par liste pour obtenir ce que vous voulez, par exemple:

si vous souhaitez conserver les espaces réservés 0.0 pour les éléments non disponibles:

[v.get(i, 0.0) for i in range(max(v.keys())+1)]

sortie:

[1.0, -2.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 3.5]

Si vous ne voulez pas de 0.0 espaces réservés, vous pouvez utiliser:

[v.get(i) for i in range(max(v.keys())+1) if v.get(i) is not None]

sortie:

[1.0, -2.0, 4.0, 3.5]

Explication:

lorsque vous utilisez range(), une liste triée sera générée afin que vous n'ayez pas à vous soucier de ce tri; elle essaiera ensuite d'obtenir les éléments du dictionnaire conformément à cette liste. Dans le premier exemple, si la clé n'existe pas, un 0.0 sera renvoyé tandis que dans le deuxième exemple, None sera renvoyé et sera ignoré à cause du if-statement dans l'expression.

MODIFIER:

Comme Christian l’a mentionné, vous pouvez modifier la 2ème option pour plus d’efficacité:

[v[i] for i in range(max(v.keys())+1) if i in v]

Cela évitera d'appeler v.get(i) deux fois.

2
Moe A

Ce n’est pas répondre strictement à la question, mais plutôt essayer de comprendre ce que vous essayez d’atteindre. Si vous essayez d'implémenter des vecteurs fragmentés, vous voudrez peut-être examiner le fichier scipy.sparse avant de passer du temps à une nouvelle implémentation.

Par exemple:

from scipy.sparse import dok_matrix
v = {3:4.0, 1:-2.0, 10:3.5, 0:1.0}
m = dok_matrix((11,1))
m.update(v)

L'avantage des matrices creuses est qu'elles peuvent (en fonction de la fraction d'éléments non nuls) prendre moins de mémoire et/ou permettre des calculs plus rapides.

0
Luca Citi