2011-03-11 14 views
72

¿Cuál es la mejor forma (mejor que en la forma convencional) de verificar si todos los elementos en una lista son únicos?Comprobando si todos los elementos en una lista son únicos

Mi enfoque actual es el uso de un Counter:

>>> x = [1, 1, 1, 2, 3, 4, 5, 6, 2] 
>>> counter = Counter(x) 
>>> for values in counter.itervalues(): 
     if values > 1: 
      # do something 

¿Puedo hacer algo mejor?

Respuesta

107

No es el más eficiente, pero sencillo y conciso:

if len(x) > len(set(x)): 
    pass # do something 

probablemente no va a hacer mucha diferencia para listas cortas.

+1

¿te refieres a ==? – Ant

+0

Esto es lo que hago también. Probablemente no sea eficiente para grandes listas aunque. – tkerwin

+0

No necesariamente, eso ejecutará el cuerpo del condicional si la lista tiene elementos que se repiten (el "#do algo" en el ejemplo). – yan

6

¿Qué le parece agregar todas las entradas a un conjunto y verificar su longitud?

len(set(x)) == len(x) 
+0

Respondió un segundo después de yan, ouch. Corto y dulce. ¿Alguna razón por la cual no usar esta solución? – jasonleonhard

9

alternativa a un set, se puede utilizar un dict.

len({}.fromkeys(x)) == len(x) 
+1

¡Una idea realmente genial! +1 –

+4

No veo absolutamente ninguna ventaja al usar un dict sobre un conjunto. Parece complicar innecesariamente las cosas. – metasoarous

17

Una solución pronta salida podría ser

def unique_values(g): 
    s = set() 
    for x in g: 
     if x in s: return False 
     s.add(x) 
    return True 

sin embargo, para casos pequeños o si temprana excitante no es el caso común entonces yo esperaría len(x) != len(set(x)) siendo el método más rápido.

+0

+1 parece ser la manera más eficiente de hacerlo. – tokland

+0

Acepté la otra respuesta ya que no estaba particularmente buscando la optimización. – user225312

+2

Puede acortar esto poniendo la siguiente línea después de 's = set()' ... 'return not any (s.add (x) si x no en s else True para x en g)' –

0

puede utilizar la sintaxis de Yan (len (x)> len (juego (x))), pero en lugar de conjunto (x), definir una función:

def f5(seq, idfun=None): 
    # order preserving 
    if idfun is None: 
     def idfun(x): return x 
    seen = {} 
    result = [] 
    for item in seq: 
     marker = idfun(item) 
     # in old Python versions: 
     # if seen.has_key(marker) 
     # but in new ones: 
     if marker in seen: continue 
     seen[marker] = 1 
     result.append(item) 
    return result 

y hacer len (x)> len (f5 (x)). Esto será rápido y también preservará el orden.

Código no se ha tomado de: http://www.peterbe.com/plog/uniqifiers-benchmark

+0

Podría ser bueno, pero no estoy buscando la optimización. – user225312

+0

esta función f5 será más lenta que con el conjunto que está mejor optimizado para la velocidad. Este código comienza a romperse cuando la lista se vuelve realmente grande debido a la costosa operación de "agregar". con grandes listas como 'x = rango (1000000) + rango (1000000)', la ejecución de conjunto (x) es más rápida que f5 (x). El orden no es un requisito en la pregunta, pero incluso ejecutar ordenado (set (x)) es aún más rápido que f5 (x) – OkezieE

66

Aquí es un revestimiento de dos que también lo hará la salida temprana:

>>> def allUnique(x): 
...  seen = set() 
...  return not any(i in seen or seen.add(i) for i in x) 
... 
>>> allUnique("ABCDEF") 
True 
>>> allUnique("ABACDEF") 
False 

Si los elementos de x no son hashable, entonces tendrá a recurrir al uso de una lista de seen:

>>> def allUnique(x): 
...  seen = list() 
...  return not any(i in seen or seen.append(i) for i in x) 
... 
>>> allUnique([list("ABC"), list("DEF")]) 
True 
>>> allUnique([list("ABC"), list("DEF"), list("ABC")]) 
False 
+3

+1 clean y no itera por toda la lista si no es necesario. – Kos

+0

+1, tarde en la fiesta, pero esta es una gran solución (y merece mucho más votos a favor). –

+0

@ paul-mcguire: ¿Estaría dispuesto a licenciar este fragmento de código bajo una licencia compatible con Apache 2.0 (por ejemplo, Apache 2, BSD de 2 3/3 líneas, MIT, X11, zlib). Me gustaría usarlo en un proyecto Apache 2.0 que estoy usando, y como los términos de la licencia de StackOverflow son _fubar_, te lo pido como el autor original. –

1

¿Qué tal esto

def is_unique(lst): 
    if not lst: 
     return True 
    else: 
     return Counter(lst).most_common(1)[0][1]==1 
11

para la velocidad:

import numpy as np 
x = [1, 1, 1, 2, 3, 4, 5, 6, 2] 
np.unique(x).size == len(x) 
1

Otro enfoque totalmente, utilizando ordenados y GroupBy:

from itertools import groupby 
is_unique = lambda seq: all(sum(1 for _ in x[1])==1 for x in groupby(sorted(seq))) 

Requiere una especie, pero salidas en el primer valor repetido.

+0

hash es más rápido que ordenar – IceArdor

2

Aquí es una función de salida temprana recursiva:

def distinct(L): 
    if len(L) == 2: 
     return L[0] != L[1] 
    H = L[0] 
    T = L[1:] 
    if (H in T): 
      return False 
    else: 
      return distinct(T)  

Es lo suficientemente rápido para mí sin necesidad de utilizar las conversiones extrañas (lento), mientras que tener un enfoque de estilo funcional.

+1

'H en T' hace una búsqueda lineal, y' T = L [1:] 'copia la parte cortada de la lista, por lo que será mucho más lenta que las otras soluciones que se han sugerido en grandes listas Creo que es O (N^2), mientras que la mayoría de los otros son O (N) (conjuntos) u O (N log N) (soluciones basadas en clasificación). – Blckknght

1

Aquí es una O recursiva (N) versión para la diversión:

def is_unique(lst): 
    if len(lst) > 1: 
     return is_unique(s[1:]) and (s[0] not in s[1:]) 
    return True 
-4

para principiantes:

def AllDifferent(s): 
    for i in range(len(s)): 
     for i2 in range(len(s)): 
      if i != i2: 
       if s[i] == s[i2]: 
        return False 
    return True 
1

Utilizando un enfoque similar en una trama de datos pandas para probar si el contenido de una columna contiene valores únicos:

if tempDF['var1'].size == tempDF['var1'].unique().size: 
    print("Unique") 
else: 
    print("Not unique") 

Para mí, este soy yo nstantaneous en una variable int en un marco de fecha que contiene más de un millón de filas.

Cuestiones relacionadas