2012-04-30 11 views
6

Duplicar posible:
Python: Retrieve items from a set¿Hay alguna manera de obtener un artículo de un conjunto en O (1) vez?

Considere el siguiente código:

>>> item1 = (1,) 
>>> item2 = (2,) 
>>> s = set([item1, item2]) 
>>> s 
set([(2,), (1,)]) 
>>> new_item = (1,) 
>>> new_item in s 
True 
>>> new_item == item1 
True 
>>> new_item is item1 
False 

Así new_item está en s porque equivale a uno de sus artículos, pero es un objeto diferente

Lo que quiero es obtener item1 de s dado new_item es en s.

Una solución que he llegado con es sencillo, pero no es muy eficiente:

def get_item(s, new_item): 
    for item in s: 
     if item == new_item: 
      return item 

>>> get_item(s, new_item) is new_item 
False 
>>> get_item(s, new_item) is item1 
True 

Otra solución parece más eficiente, pero en realidad no funciona:

def get_item_using_intersection1(s, new_item): 
    return set([new_item]).intersection(s).pop() 

Tampoco éste:

def get_item_using_intersection2(s, new_item): 
    return s.intersection(set([new_item])).pop() 

Porque la intersección funciona de manera indefinida:

>>> get_item_using_intersection1(s, new_item) is new_item 
True 
>>> get_item_using_intersection1(s, new_item) is item1 
False 

>>> get_item_using_intersection2(s, new_item) is new_item 
True 
>>> get_item_using_intersection2(s, new_item) is item1 
False 

Si esto es importante, estoy usando Python 2.7 x64 en Windows 7, pero necesito una solución multiplataforma.


Gracias a todos. Se me ocurrió la siguiente solución temporal:

class SearchableSet(set): 

    def find(self, item): 
     for e in self: 
      if e == item: 
       return e 

que será sustituido en el futuro con la siguiente solución (que es muy incompleta en este momento):

class SearchableSet(object): 

    def __init__(self, iterable=None): 
     self.__data = {} 
     if iterable is not None: 
      for e in iterable: 
       self.__data[e] = e 

    def __iter__(self): 
     return iter(self.__data) 

    def __len__(self): 
     return len(self.__data) 

    def __sub__(self, other): 
     return SearchableSet(set(self).__sub__(set(other))) 

    def add(self, item): 
     if not item in self: 
      self.__data[item] = item 

    def find(self, item): 
     return self.__data.get(item) 
+1

Pero ... La "solución ineficiente" que surgió ya es lineal. – kennytm

+0

Creo que quiere decir * constante * tiempo –

+0

@KennyTM, gracias, he editado el título de mi pregunta. – utapyngo

Respuesta

12

No utilice una set, a continuación, . Solo use un dict que se asigna algún valor a sí mismo. En su caso, se asigna:

d[item1] = item1 
d[item2] = item2 

Así que todo lo que es igual a item1 se encontrará en d, pero el valor es item1 sí. Y es mucho mejor que el tiempo lineal ;-)

P.S. Espero haber entendido correctamente la intención de tu pregunta. Si no, por favor aclararlo.

+0

Gracias. Sé que es posible usar 'dict's pero también sé que técnicamente es posible quedarse con' set's (suponiendo que hay un método interno que puede encontrar un elemento mediante hash). Además, no quiero volver a escribir mi código anterior porque utilizo las operaciones de configuración de forma intensiva. – utapyngo

+7

@utapyngo: es mejor volver a escribir el código anterior si es incorrecto. 'set' simplemente no está diseñado para esto: use una estructura de datos más apropiada. –

+0

¿Cómo hacer inersection, union y diferencia de tales dicts en tiempo lineal? – utapyngo

2

Si es absolutamente necesario la junta (1) consulta de e identidad objeto (no sólo la igualdad) y operaciones de conjunto rápida (sin tener que crear nuevos juegos cada vez que desee realizar operaciones de ajuste), entonces uno bastante El enfoque directo es usar ambos a dict y set. Tendría que mantener ambas estructuras para mantenerlas sincronizadas, pero esto le permitiría mantener el acceso O (1) (solo que con un factor constante mayor).(Y tal vez esto es hacia lo que se dirige con su "futura solución que está muy incompleta ahora" en su edición).

Sin embargo, no ha mencionado el volumen de datos con los que está trabajando o qué tipo de problemas de rendimiento que está teniendo, en su caso. Entonces no estoy convencido de que realmente necesites hacer esto. Podría ser que dict con la creación set según sea necesario, o set con búsqueda lineal, ya sea lo suficientemente rápido.

Cuestiones relacionadas