2009-09-30 9 views
8

Tengo una lista en Python que genero como parte del programa. Tengo una fuerte suposición de que estos son todos diferentes, y compruebo esto con una afirmación.¿Cuál es la forma más pitónica de garantizar que todos los elementos de una lista sean diferentes?

Esta es la forma en que lo hago ahora:

Si hay dos elementos:

try: 
    assert(x[0] != x[1]) 
except: 
    print debug_info 
    raise Exception("throw to caller") 

Si hay tres:

try: 
    assert(x[0] != x[1]) 
    assert(x[0] != x[2]) 
    assert(x[1] != x[2]) 
except: 
    print debug_info 
    raise Exception("throw to caller") 

Y si alguna vez tengo que hacer esto con cuatro elementos me volveré loco.

¿Hay una manera mejor de asegurarse de que todos los elementos de la lista sean únicos?

Respuesta

26

Tal vez algo como esto:

if len(x) == len(set(x)): 
    print "all elements are unique" 
else: 
    print "elements are not unique" 
+0

respuesta Muy inteligente – foosion

+2

Se podía almacenarlos en un conjunto en el primer lugar para asegurarse de que son todos únicos. O guárdelos en un conjunto, pero antes de agregarlos al conjunto, verifique la membresía. Pero esto definitivamente funciona si no tienes control sobre el formato de entrada. –

+0

conjuntos no conservan necesariamente el orden, lo que podría ser importante. –

7

¿Qué tal esto:

if len(x) != len(set(x)): 
    raise Exception("throw to caller") 

Esto supone que los elementos en x son hashable.

2

Afortunadamente, todos los elementos en su secuencia son inmutables; de lo contrario, no podrá llamar al set en la secuencia.

>>> set(([1,2], [3,4])) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'list' 

Si hacer tener elementos mutables, no se puede desmenuzar los artículos y usted será más o menos tiene que comprobar repetidamente a través de la lista:

def isUnique(lst): 
    for i,v in enumerate(lst): 
     if v in lst[i+1:]: 
      return False 
    return True 

>>> isUnique(([1,2], [3,4])) 
True 
>>> isUnique(([1,2], [3,4], [1,2])) 
False 
1

Mientras construye la lista, puede verificar si el valor ya existe, por ejemplo:

if x in y: 
    raise Exception("Value %s already in y" % x) 
else: 
    y.append(x) 

El beneficio de esto es que se informará la variable de enfrentamiento.

0

Se puede procesar la lista para crear un conocido-a-ser-única copia:

def make_unique(seq): 
    t = type(seq) 
    seen = set() 
    return t(c for c in seq if not (c in seen or seen.add(c))) 

O si los elementos seq no son hashable:

def unique1(seq): 
    t = type(seq) 
    seen = [] 
    return t(c for c in seq if not (c in seen or seen.append(c))) 

Y esto mantendrá los artículos en orden (omitiendo duplicados, por supuesto).

18

Las respuestas más populares son O (N) (¡buenas! -) pero, como señalan @Paul y @Mark, requieren que los elementos de la lista sean fáciles de manipular. Los enfoques propuestos por @Paul y @Mark para los elementos que no se pueden modificar son generales, pero toman O (N al cuadrado), es decir, mucho.

Si los elementos de su lista no son aptos pero son comparables, puede hacerlo mejor ... este es un enfoque que siempre funciona lo más rápido posible dada la naturaleza de los elementos de la lista.

import itertools 

def allunique(L): 
    # first try sets -- fastest, if all items are hashable 
    try: 
    return len(L) == len(set(L)) 
    except TypeError: 
    pass 
    # next, try sort -- second fastest, if items are comparable 
    try: 
    L1 = sorted(L) 
    except TypeError: 
    pass 
    else: 
    return all(len(list(g))==1 for k, g in itertools.groupby(L1)) 
    # fall back to the slowest but most general approach 
    return all(v not in L[i+1:] for i, L in enumerate(L)) 

Esto es O (N) cuando sea factible (todos los artículos hashable), O (N log N) como el repliegue más frecuente (algunos artículos unhashable, pero todo comparable), O (N al cuadrado) donde inevitable (algunos elementos son inigualables, por ejemplo, dicts y algunos no comparables, por ejemplo, números complejos).

La inspiración para este código proviene de una vieja receta del gran Tim Peters, que difería en realidad produciendo una lista de artículos únicos (y también fue tan reciente que set no existía - tenía que usar un dict. ..! -), pero básicamente enfrentaron problemas idénticos.

+0

Extraño a Tim. Debe invitarlo a almorzar nuevamente pronto. – holdenweb

+0

Heh, lo extraño más (¡ha sido más largo!), Pero supongo que es poco práctico para cualquiera de nosotros volar de costa a costa solo para almorzar ;-). –

+0

¿Quiso decir 'v not in L [i + 1:] para v, i en enumerate (L)'? – chepner

0

me gustaría utilizar esto:

mylist = [1,2,3,4] 
is_unique = all(mylist.count(x) == 1 for x in mylist) 
+0

'O (n ** 2)', ¿no? – SilentGhost

Cuestiones relacionadas