88 votes

Quel est le moyen le plus propre de faire un tri plus uniq sur une liste Python?

Considérez une liste Python my_list contenant ['foo', 'foo', 'bar'].

Quelle est la manière la plus Pythonic de uniquify et trier une liste ?
(pensez à cat my_list | sort | uniq)

C'est ainsi que je le fais actuellement et même si cela fonctionne, je suis sûr qu'il y a de meilleures façons de le faire.

my_list = []
...
my_list.append("foo")
my_list.append("foo")
my_list.append("bar")
...
my_list = set(my_list)
my_list = list(my_list)
my_list.sort()

144voto

Ignacio Vazquez-Abrams Points 312628
ma_liste = sorted(set(ma_liste))

20voto

tzot Points 32224
# Python ≥ 2.4
# because of (generator expression) and itertools.groupby, sorted

import itertools

def sort_uniq(sequence):
    return (x[0] for x in itertools.groupby(sorted(sequence)))

Plus rapide:

import itertools, operator
import sys

if sys.hexversion < 0x03000000:
    mapper= itertools.imap # 2.4 ≤ Python < 3
else:
    mapper= map # Python ≥ 3

def sort_uniq(sequence):
    return mapper(
        operator.itemgetter(0),
        itertools.groupby(sorted(sequence)))

Les deux versions renvoient un générateur, donc vous voudrez peut-être fournir le résultat au type liste :

sequence= list(sort_uniq(sequence))

Notez que cela fonctionnera également avec des éléments non hasheables :

>>> list(sort_uniq([[0],[1],[0]]))
[[0], [1]]

8voto

Mike Graham Points 22480

La solution directe est fournie par Ignacio - sorted(set(foo)).

Si vous avez des données uniques, il y a de bonnes chances que vous ne vouliez pas simplement faire sorted(set(...)) mais plutôt stocker un ensemble tout le temps et parfois extraire une version triée des valeurs. (À ce stade, cela commence à ressembler à ce que les gens utilisent souvent une base de données, aussi.)

Si vous avez une liste triée et que vous voulez vérifier l'appartenance de manière logarithmique et ajouter un élément dans le pire des cas en temps linéaire, vous pouvez utiliser le module bisect.

Si vous voulez toujours garder cette condition et que vous voulez simplifier les choses ou améliorer certaines opérations, vous pourriez envisager blist.sortedset.

2voto

taleinat Points 2525

D'autres ont mentionné sorted(set(my_list)), qui fonctionne pour les valeurs hashables telles que les chaînes de caractères, les nombres et les tuples, mais pas pour les types non hashables tels que les listes.

Pour obtenir une liste triée des valeurs de n'importe quel type pouvant être trié, sans doublons :

from itertools import izip, islice
def unique_sorted(values):
    "Retourne une liste triée des valeurs données, sans doublons."
    values = sorted(values)
    if not values:
        return []
    consecutive_pairs = izip(values, islice(values, 1, len(values)))
    result = [a for (a, b) in consecutive_pairs if a != b]
    result.append(values[-1])
    return result

Ceci peut être simplifié davantage en utilisant les recettes "pairwise" ou "unique_justseen" de la documentation itertools.

-3voto

andreypopp Points 2326

Je ne peux pas dire que c'est une façon propre de faire ça, mais juste pour le plaisir :

ma_liste = [x for x in sorted(ma_liste) if not x in locals()["_[1]"]]

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X