La suppression des doublons dans une liste de listes

J'ai une liste de listes en Python:

k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [4]]

Et je veux supprimer dupliquer des éléments. A si c'est une liste normale pas de listes que je pouvais utilisé set. Mais regrettable que la liste n'est pas hashable et ne peut pas faire de ensemble de listes. Seulement de tuples. Donc, je peux tourner toutes les listes les tuples puis utiliser ensemble et de retour à des listes. Mais ce n'est pas rapide.

Comment ce fait de la manière la plus efficace?

Le résultat de la liste ci-dessus devraient être:

k = [[5, 6, 2], [1, 2], [3], [4]]

Je ne se soucient pas de préserver l'ordre.

Remarque: cette question est similaire mais pas tout à fait ce dont j'ai besoin. Cherché mais n'ai pas trouver la copie exacte.


Benchmarking:

import itertools, time
class Timer(object):
def __init__(self, name=None):
self.name = name
def __enter__(self):
self.tstart = time.time()
def __exit__(self, type, value, traceback):
if self.name:
print '[%s]' % self.name,
print 'Elapsed: %s' % (time.time() - self.tstart)
k = [[1, 2], [4], [5, 6, 2], [1, 2], [3], [5, 2], [6], [8], [9]] * 5
N = 100000
print len(k)
with Timer('set'):
for i in xrange(N):
kt = [tuple(i) for i in k]
skt = set(kt)
kk = [list(i) for i in skt]
with Timer('sort'):
for i in xrange(N):
ks = sorted(k)
dedup = [ks[i] for i in xrange(len(ks)) if i == 0 or ks[i] != ks[i-1]]
with Timer('groupby'):
for i in xrange(N):
k = sorted(k)
dedup = list(k for k, _ in itertools.groupby(k))
with Timer('loop in'):
for i in xrange(N):
new_k = []
for elem in k:
if elem not in new_k:
new_k.append(elem)

"boucle" (quadratique de la méthode) le plus rapide de tous pour de courtes listes. Pendant de longues listes, il est plus rapide que tout le monde sauf groupby méthode. Est-il logique?

Pour la courte liste (celle dans le code), 100000 itérations:

[set] Elapsed: 1.3900001049
[sort] Elapsed: 0.891000032425
[groupby] Elapsed: 0.780999898911
[loop in] Elapsed: 0.578000068665

Pour plus de la liste (celui dans le code dupliqué 5 fois):

[set] Elapsed: 3.68700003624
[sort] Elapsed: 3.43799996376
[groupby] Elapsed: 1.03099989891
[loop in] Elapsed: 1.85900020599
  • Par "ce n'est pas rapide", vous voulez dire que vous avez chronométré et il n'est pas assez rapide pour votre application, ou que vous pensez qu'il n'est pas rapide?
  • il semble juste comme trop de copie d'être intelligent méthode. désolé, le gut feeling. copie des listes de n-uplets, puis dans le jeu, puis retour à la liste de listes (copie de nouveau tuples, listes)
  • ce n'est pas la façon Python fonctionne, rien ne pourra être copié, juste de nouveaux conteneurs pour les éléments existants ( bien que pour les entiers, c'est à peu près le même )
  • 1. les horaires pour les méthodes à l'aide de tri sont dégonflés, parce que le "k" est le rebond de la triés variante. 2. La dernière méthode est plus rapide, car la méthode utilisée pour générer les données de test vous laisse avec au plus 4 éléments distincts. Essayez de qqch. comme K = [[int(u) pour u dans str(aléatoire.randrange(1, 1000))] for _ in range(100)]
  • merci fixe. mais encore, la méthode de boucle est rapide, même lorsqu'il n'existe qu'un seul doublon dans la liste des 10
  • Oui, pour les petits de saisie des listes, "boucle" sera plus rapide. Sa complexité est en O(mn), où m est le nombre d'éléments uniques (de n). De sorte que le moins unique, il y a d'éléments, plus il est (c'est à dire linéaire pour les listes avec un seul et unique élément). Pour de courtes listes, la constante de facteurs à la fois de "trier" et "groupe" sont trop élevés pour eux d'être plus rapide que la "boucle".
  • pour mesurer la performance d'un cas spécifique, l'utilisation de la bibliothèque standard du module de timeit à l'invite du shell (plus simple et plus solide, beaucoup mieux que d'intégrer dans le code). Je vais modifier mon Un de le montrer.
  • comme Torsten dit, la boucle est rapide avec de petits échantillons. C'est tout à fait normal dans des algorithmes engager dans de petits coûts constants (création d'une liste vide vd. création d'une liste à partir d'un n-uplet). Mais il croit toujours quadratiquement, ce qui signifie que les méthodes linéaires sera plus rapide que la boucle à un certain point.
  • Je voudrais juste faire remarquer que vous êtes seuls des essais sur ce que j'appelle "court" des listes. Une "longue" liste pour m'aurait peut-être ou 10k 100k éléments, peut-être quelques millions de dollars.

InformationsquelleAutor zaharpopov | 2010-02-06