2012-07-30 9 views
9

Me gustaría comparar varios objetos y devolver True solo si todos los objetos no son iguales entre ellos. Intenté usar el código a continuación, pero no funciona. Si obj1 y obj3 son iguales y obj2 y obj3 no son iguales, el resultado es True.Python: determina si cualquier elemento en secuencia es igual a cualquier otro

obj1 != obj2 != obj3 

Tengo más de 3 objetos para comparar. Con el siguiente código está fuera de cuestión:

all([obj1 != obj2, obj1 != obj3, obj2 != obj3]) 
+0

es el número de objetos fijos o variables? ¿Son elementos de una matriz o en variables individuales? –

Respuesta

20

@ Michael Hoffman es bueno si los objetos son todos hashable. Si no, puede utilizar itertools.combinations:

>>> all(a != b for a, b in itertools.combinations(['a', 'b', 'c', 'd', 'a'], 2)) 
False 
>>> all(a != b for a, b in itertools.combinations(['a', 'b', 'c', 'd'], 2)) 
True 
18

Si los objetos son todos hashable, a continuación, puede ver si un frozenset de la secuencia de los objetos tiene la misma longitud que la propia secuencia:

def all_different(objs): 
    return len(frozenset(objs)) == len(objs) 

Ejemplo:

>>> all_different([3, 4, 5]) 
True 
>>> all_different([3, 4, 5, 3]) 
False 
+0

¡Maldición! vencerme por 10 segundos – inspectorG4dget

+1

Tenga en cuenta que esto no funcionará si los objetos no son reemplazables. – BrenBarn

+0

Esto no funciona si uno (o todos) de los objetos es inhoshable (por ejemplo, una lista) – mgilson

3

se puede comprobar que todos los elementos de una lista son únicos mediante la conversión a un conjunto. La respuesta de

my_obs = [obj1, obj2, obj3] 
all_not_equal = len(set(my_obs)) == len(my_obs) 
4
from itertools import combinations 
all(x != y for x, y in combinations(objs, 2)) 
+1

Eso es O (n^2) comparaciones - MUCHO para listas grandes. – inspectorG4dget

6

Si los objetos son unhashable pero ordenable (por ejemplo, listas) entonces se puede transformar la solución itertools de O (n^2) a O (log n n) por la clasificación:

def all_different(*objs): 
    s = sorted(objs) 
    return all(x != y for x, y in zip(s[:-1], s[1:])) 

He aquí una aplicación plena:

def all_different(*objs): 
    try: 
     return len(frozenset(objs)) == len(objs) 
    except TypeError: 
     try: 
      s = sorted(objs) 
      return all(x != y for x, y in zip(s[:-1], s[1:])) 
     except TypeError: 
      return all(x != y for x, y in itertools.combinations(objs, 2)) 
+0

El control de la capacidad de carga es demasiado complejo (y también ligeramente incorrecto). La forma idiomática de hacer esto en Python es intentar construir un 'frozenset()' y atrapar 'TypeError' si esto falla. (La prueba es un poco incorrecta porque 'isinstance (obj, collections.Hashable)' siendo 'True' no garantiza que el objeto sea realmente hashable. Solo verifica si el objeto tiene un tipo que le permite, en principio, ser hasheado. ([],) 'como un contraejemplo.) –

+0

@SvenMarnach gracias, corregidos. – ecatmur

Cuestiones relacionadas