web-dev-qa-db-fra.com

Trier une liste de tuples par seconde valeur, inverse = Vrai puis par clé, inverse = Faux

Je dois d'abord trier un dictionnaire, les valeurs avec reverse=True, et pour répéter les valeurs, trier par clés, reverse=False

Jusqu'à présent, j'ai

dict = [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]
sorted(dict.items(), key=lambda x: (x[1],x[1]), reverse=True)

qui revient ...

[('B', 3), ('A', 2), ('J', 1), ('I', 1), ('A', 1)]

mais j'en ai besoin:

[('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

comme vous pouvez le voir, lorsque les valeurs sont égales, je ne peux trier la clé que de manière décroissante comme spécifié ... Mais comment puis-je les faire trier de manière croissante?

27
Nicolas Hung

Les éléments suivants fonctionnent avec votre entrée:

d = [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]
sorted(d,key=lambda x:(-x[1],x[0]))

Comme vos "valeurs" sont numériques, vous pouvez facilement inverser l'ordre de tri en changeant le signe.

En d'autres termes, ce tri met les choses en ordre par valeur (-x[1]) (le signe négatif met d'abord les grands nombres) puis pour les nombres qui sont les mêmes, il ordonne selon la clé (x[0]).

Si vos valeurs ne peuvent pas être "annulées" si facilement pour placer les gros éléments en premier, une solution simple consiste à trier deux fois:

from operator import itemgetter
d.sort(key=itemgetter(0))
d.sort(key=itemgetter(1),reverse=True)

ce qui fonctionne car le tri de python est stable.

41
mgilson
In [4]: l = [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

In [5]: sorted(l, key=lambda (x,y):(-y,x))
Out[5]: [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]
3
NPE

vous pouvez utiliser collections.defaultdict:

In [48]: from collections import defaultdict

In [49]: dic=[('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]

In [50]: d=defaultdict(list)

In [51]: for x,y in dic:
    d[y].append(x)
    d[y].sort()          #sort the list

maintenant d est quelque chose comme:

 defaultdict(<type 'list'>, {1: ['A', 'I', 'J'], 2: ['A'], 3: ['B']}

c'est-à-dire un nouveau dict avec 1,2,3... comme clés et les alphabets correspondants stockés dans des listes comme valeurs.

Vous pouvez maintenant parcourir la sorted(d.items) et obtenir le résultat souhaité en utilisant itertools.chain() et itertools.product().

In [65]: l=[ product(y,[x]) for x,y in sorted(d.items(),reverse=True)]

In [66]: list(chain(*l))
Out[66]: [('B', 3), ('A', 2), ('A', 1), ('I', 1), ('J', 1)]
1
Ashwini Chaudhary