2011-11-30 15 views
6

Tengo un dict donde algunos de los valores no son hashable. Necesito alguna forma de comparar dos grupos desordenados de estos para asegurar que contengan elementos iguales. No puedo usar listas porque la igualdad de la lista tiene en cuenta el orden, pero los conjuntos no funcionan porque los dictados no son hashables. Eché un vistazo a los documentos de Python, y lo único que parece útil es la vista de un dict, que es manejable en algunas circunstancias, pero en este caso esto tampoco ayuda, ya que uno de los valores es un objeto que contiene listas, lo que significa que la vista del dict no será manejable tampoco.¿Colección desordenada para objetos irreemplazables?

¿Hay un contenedor estándar para situaciones como esta, o debería simplemente usar listas y recorrer cada elemento en ambas listas y asegurar que un elemento igual esté en algún lugar de la otra lista?

+2

He tenido situaciones similares ons donde copié el dict en una lista ordenada temporal solo para la comparación. El tamaño u otras consideraciones pueden hacer que esta sea una buena opción para su caso o no. –

+0

¿Qué es exactamente lo que los hace inigualables? Si no son manejables, ¿cómo exactamente los comparas para la igualdad? –

+0

@Karl Uno de los valores en el dict es una lista. – Macha

Respuesta

11

Cuando no existen entradas duplicadas, las opciones habituales son:

  1. Si los elementos son hashable: set(a) == set(b)

  2. Si los elementos son que se puede pedir: sorted(a) == sorted(b)

  3. Si todo usted tiene es la igualdad: len(a) == len(b) and all(x in b for x in a)

Si tiene duplicados y sus asuntos multiplicidad, las opciones son:

  1. Si los elementos son hashable: Counter(a) == Counter(b)

  2. Si los elementos son que se puede pedir: sorted(a) == sorted(b)

  3. Si todo lo que tiene es la igualdad: len(a) == len(b) and all(a.count(x) == b.count(x) for x in a)

2

Creo que el método más simple es usar listas.

group_1 = my_dict_1.values() 
group_2 = my_dict_2.values() 

Su comparación no será tan simple como si el orden importaba, o si los valores fueron hashable, pero el siguiente debería funcionar:

def contain_the_same(group_1, group_2): 
    for item in group_1: 
     if item not in group_2: 
      return False 
     else: 
      group_2.pop(group_2.index(item)) 
    if len(group_2) != 0: 
     return False 
    return True 

Esto debería ser capaz de manejar objetos unhashable bien :

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

Una advertencia: Esto dará como resultado falso si hay duplicados en una lista, pero no en la otra. Esto requeriría algunas modificaciones si quisiera que ese sea un caso permitido.

Editar: Aún más fácil:

sorted(my_dict_1.values()) == sorted(my_dict_1.values()) 

Incluso se parece a esto es el doble de rápido como mi contain_the_same función:

>>> timeit("contain_the_same([5,1,2,[3,2,1,[1]]], [1,[3,2,1,[1]],2,5])", 
      "from __main__ import contain_the_same", number=10000)/10000 
8.868489032757054e-06 
>>>timeit("sorted([5,1,2,[3,2,1,[1]]]) == sorted([1,[3,2,1,[1]],2,5])", 
      number=10000)/10000 
4.928951884845034e-06 

A pesar de que no sería tan fácil de extender a la caso en que los duplicados están permitidos

Cuestiones relacionadas