web-dev-qa-db-fra.com

Quelle est la façon la plus propre de faire un tri plus uniq sur une liste Python?

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

Quelle est la façon la plus pythonique de niquify et de trier une liste?
(pense cat my_list | sort | uniq)

C'est ainsi que je le fais actuellement et bien que cela fonctionne, je suis sûr qu'il existe 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()
55
knorv
my_list = sorted(set(my_list))
92
# 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, vous pouvez donc vouloir fournir le résultat au type de liste:

sequence= list(sort_uniq(sequence))

Notez que cela fonctionnera également avec les articles non hachables:

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

La solution simple est fournie par Ignacio —sorted(set(foo)).

Si vous avez des données uniques, il y a une chance raisonnable que vous ne souhaitiez 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 au genre de chose pour laquelle les gens utilisent souvent une base de données.)

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

Si vous souhaitez conserver cette condition tout le temps et que vous souhaitez simplifier les choses ou améliorer le fonctionnement de certaines opérations, vous pouvez envisager blist.sortedset .

5
Mike Graham

D'autres ont mentionné trié (set (ma_liste)), qui fonctionne pour les valeurs lavables telles que les chaînes, les nombres et les tuples, mais pas pour les types non lavables tels que les listes.

Pour obtenir une liste triée de valeurs de tout type triable, sans doublons:

from itertools import izip, islice
def unique_sorted(values):
    "Return a sorted list of the given values, without duplicates."
    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

Cela peut être encore simplifié en utilisant les recettes "par paire" ou "unique_justseen" de la documentation itertools .

2
taleinat